Files
dsProject/dsLightRag/static/jsmind/jsmind.screenshot.js
2025-08-14 15:45:08 +08:00

352 lines
12 KiB
JavaScript

/**
* @license BSD
* @copyright 2014-2025 hizzgdev@163.com
*
* Project Home:
* https://github.com/hizzgdev/jsmind/
*/
(function ($w) {
'use strict';
console.warn("The version is outdated. see details: https://hizzgdev.github.io/jsmind/es6/")
var __name__ = 'jsMind';
var jsMind = $w[__name__];
if (!jsMind) { return; }
if (typeof jsMind.screenshot != 'undefined') { return; }
var $d = $w.document;
var $c = function (tag) { return $d.createElement(tag); };
var css = function (cstyle, property_name) {
return cstyle.getPropertyValue(property_name);
};
var is_visible = function (cstyle) {
var visibility = css(cstyle, 'visibility');
var display = css(cstyle, 'display');
return (visibility !== 'hidden' && display !== 'none');
};
var jcanvas = {};
jcanvas.rect = function (ctx, x, y, w, h, r) {
if (w < 2 * r) r = w / 2;
if (h < 2 * r) r = h / 2;
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
};
jcanvas.text_multiline = function (ctx, text, x, y, w, h, lineheight) {
var line = '';
var text_len = text.length;
var chars = text.split('');
var test_line = null;
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
for (var i = 0; i < text_len; i++) {
test_line = line + chars[i];
if (ctx.measureText(test_line).width > w && i > 0) {
ctx.fillText(line, x, y);
line = chars[i];
y += lineheight;
} else {
line = test_line;
}
}
ctx.fillText(line, x, y);
};
jcanvas.text_ellipsis = function (ctx, text, x, y, w, h) {
var center_y = y + h / 2;
var text = jcanvas.fittingString(ctx, text, w);
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(text, x, center_y, w);
};
jcanvas.fittingString = function (ctx, text, max_width) {
var width = ctx.measureText(text).width;
var ellipsis = '…';
var ellipsis_width = ctx.measureText(ellipsis).width;
if (width <= max_width || width <= ellipsis_width) {
return text;
} else {
var len = text.length;
while (width >= max_width - ellipsis_width && len-- > 0) {
text = text.substring(0, len);
width = ctx.measureText(text).width;
}
return text + ellipsis;
}
};
jcanvas.image = function (ctx, url, x, y, w, h, r, rotation, callback) {
var img = new Image();
img.onload = function () {
ctx.save();
ctx.translate(x, y);
ctx.save();
ctx.beginPath();
jcanvas.rect(ctx, 0, 0, w, h, r);
ctx.closePath();
ctx.clip();
ctx.translate(w / 2, h / 2);
ctx.rotate(rotation * Math.PI / 180);
ctx.drawImage(img, -w / 2, -h / 2);
ctx.restore();
ctx.restore();
!!callback && callback();
}
img.src = url;
};
jsMind.screenshot = function (jm) {
this.jm = jm;
this.canvas_elem = null;
this.canvas_ctx = null;
this._inited = false;
};
jsMind.screenshot.prototype = {
init: function () {
if (this._inited) { return; }
console.log('init');
var c = $c('canvas');
var ctx = c.getContext('2d');
this.canvas_elem = c;
this.canvas_ctx = ctx;
this.jm.view.e_panel.appendChild(c);
this._inited = true;
this.resize();
},
shoot: function (callback) {
this.init();
this._draw(function () {
!!callback && callback();
this.clean();
}.bind(this));
this._watermark();
},
shootDownload: function () {
this.shoot(function () {
this._download();
}.bind(this));
},
shootAsDataURL: function (callback) {
this.shoot(function () {
!!callback && callback(this.canvas_elem.toDataURL());
}.bind(this));
},
resize: function () {
if (this._inited) {
this.canvas_elem.width = this.jm.view.size.w;
this.canvas_elem.height = this.jm.view.size.h;
}
},
clean: function () {
var c = this.canvas_elem;
this.canvas_ctx.clearRect(0, 0, c.width, c.height);
},
_draw: function (callback) {
var ctx = this.canvas_ctx;
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
this._draw_lines(function () {
this._draw_nodes(callback);
}.bind(this));
},
_watermark: function () {
var c = this.canvas_elem;
var ctx = this.canvas_ctx;
ctx.textAlign = 'right';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#000';
ctx.font = '11px Verdana,Arial,Helvetica,sans-serif';
ctx.fillText('github.com/hizzgdev/jsmind', c.width - 5.5, c.height - 2.5);
ctx.textAlign = 'left';
ctx.fillText($w.location, 5.5, c.height - 2.5);
},
_draw_lines: function (callback) {
this.jm.view.graph.copy_to(this.canvas_ctx, callback);
},
_draw_nodes: function (callback) {
var nodes = this.jm.mind.nodes;
var node;
for (var nodeid in nodes) {
node = nodes[nodeid];
this._draw_node(node);
}
function check_nodes_ready() {
console.log('check_node_ready' + new Date());
var allOk = true;
for (var nodeid in nodes) {
node = nodes[nodeid];
allOk = allOk & node.ready;
}
if (!allOk) {
$w.setTimeout(check_nodes_ready, 200);
} else {
$w.setTimeout(callback, 200);
}
}
check_nodes_ready();
},
_draw_node: function (node) {
var ctx = this.canvas_ctx;
var view_data = node._data.view;
var node_element = view_data.element;
var ncs = getComputedStyle(node_element);
if (!is_visible(ncs)) {
node.ready = true;
return;
}
var bgcolor = css(ncs, 'background-color');
var round_radius = parseInt(css(ncs, 'border-top-left-radius'));
var color = css(ncs, 'color');
var padding_left = parseInt(css(ncs, 'padding-left'));
var padding_right = parseInt(css(ncs, 'padding-right'));
var padding_top = parseInt(css(ncs, 'padding-top'));
var padding_bottom = parseInt(css(ncs, 'padding-bottom'));
var text_overflow = css(ncs, 'text-overflow');
var font = css(ncs, 'font-style') + ' ' +
css(ncs, 'font-variant') + ' ' +
css(ncs, 'font-weight') + ' ' +
css(ncs, 'font-size') + '/' + css(ncs, 'line-height') + ' ' +
css(ncs, 'font-family');
var rb = {
x: view_data.abs_x,
y: view_data.abs_y,
w: view_data.width + 1,
h: view_data.height + 1
};
var tb = {
x: rb.x + padding_left,
y: rb.y + padding_top,
w: rb.w - padding_left - padding_right,
h: rb.h - padding_top - padding_bottom
};
ctx.font = font;
ctx.fillStyle = bgcolor;
ctx.beginPath();
jcanvas.rect(ctx, rb.x, rb.y, rb.w, rb.h, round_radius);
ctx.closePath();
ctx.fill();
ctx.fillStyle = color;
if ('background-image' in node.data) {
var backgroundUrl = css(ncs, 'background-image').slice(5, -2);
node.ready = false;
var rotation = 0;
if ('background-rotation' in node.data) {
rotation = node.data['background-rotation'];
}
jcanvas.image(ctx, backgroundUrl, rb.x, rb.y, rb.w, rb.h, round_radius, rotation,
function () {
node.ready = true;
});
}
if (!!node.topic) {
if (text_overflow === 'ellipsis') {
jcanvas.text_ellipsis(ctx, node.topic, tb.x, tb.y, tb.w, tb.h);
} else {
var line_height = parseInt(css(ncs, 'line-height'));
jcanvas.text_multiline(ctx, node.topic, tb.x, tb.y, tb.w, tb.h, line_height);
}
}
if (!!view_data.expander) {
this._draw_expander(view_data.expander);
}
if (!('background-image' in node.data)) {
node.ready = true;
}
},
_draw_expander: function (expander) {
var ctx = this.canvas_ctx;
var ncs = getComputedStyle(expander);
if (!is_visible(ncs)) { return; }
var style_left = css(ncs, 'left');
var style_top = css(ncs, 'top');
var font = css(ncs, 'font');
var left = parseInt(style_left);
var top = parseInt(style_top);
var is_plus = expander.innerHTML === '+';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(left + 7, top + 7, 5, 0, Math.PI * 2, true);
ctx.moveTo(left + 10, top + 7);
ctx.lineTo(left + 4, top + 7);
if (is_plus) {
ctx.moveTo(left + 7, top + 4);
ctx.lineTo(left + 7, top + 10);
}
ctx.closePath();
ctx.stroke();
},
_download: function () {
var c = this.canvas_elem;
var name = this.jm.mind.name + '.png';
if (navigator.msSaveBlob && (!!c.msToBlob)) {
var blob = c.msToBlob();
navigator.msSaveBlob(blob, name);
} else {
var bloburl = this.canvas_elem.toDataURL();
var anchor = $c('a');
if ('download' in anchor) {
anchor.style.visibility = 'hidden';
anchor.href = bloburl;
anchor.download = name;
$d.body.appendChild(anchor);
var evt = $d.createEvent('MouseEvents');
evt.initEvent('click', true, true);
anchor.dispatchEvent(evt);
$d.body.removeChild(anchor);
} else {
location.href = bloburl;
}
}
},
jm_event_handle: function (type, data) {
if (type === jsMind.event_type.resize) {
this.resize();
}
}
};
var screenshot_plugin = new jsMind.plugin('screenshot', function (jm) {
var jss = new jsMind.screenshot(jm);
jm.screenshot = jss;
jm.shoot = function () {
jss.shoot();
};
jm.add_event_listener(function (type, data) {
jss.jm_event_handle.call(jss, type, data);
});
});
jsMind.register_plugin(screenshot_plugin);
})(window);