/* * Released under BSD License * Copyright (c) 2014-2021 hizzgdev@163.com * * Project Home: * https://github.com/hizzgdev/jsmind/ */ (function ($w) { 'use strict'; 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('hizzgdev.github.io/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);