1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | (function ($w) {
|
10 | 'use strict';
|
11 | console.warn("The version is outdated. see details: https://hizzgdev.github.io/jsmind/es6/")
|
12 | var __name__ = 'jsMind';
|
13 | var jsMind = $w[__name__];
|
14 | if (!jsMind) { return; }
|
15 | if (typeof jsMind.screenshot != 'undefined') { return; }
|
16 |
|
17 | var $d = $w.document;
|
18 | var $c = function (tag) { return $d.createElement(tag); };
|
19 |
|
20 | var css = function (cstyle, property_name) {
|
21 | return cstyle.getPropertyValue(property_name);
|
22 | };
|
23 | var is_visible = function (cstyle) {
|
24 | var visibility = css(cstyle, 'visibility');
|
25 | var display = css(cstyle, 'display');
|
26 | return (visibility !== 'hidden' && display !== 'none');
|
27 | };
|
28 | var jcanvas = {};
|
29 | jcanvas.rect = function (ctx, x, y, w, h, r) {
|
30 | if (w < 2 * r) r = w / 2;
|
31 | if (h < 2 * r) r = h / 2;
|
32 | ctx.moveTo(x + r, y);
|
33 | ctx.arcTo(x + w, y, x + w, y + h, r);
|
34 | ctx.arcTo(x + w, y + h, x, y + h, r);
|
35 | ctx.arcTo(x, y + h, x, y, r);
|
36 | ctx.arcTo(x, y, x + w, y, r);
|
37 | };
|
38 |
|
39 | jcanvas.text_multiline = function (ctx, text, x, y, w, h, lineheight) {
|
40 | var line = '';
|
41 | var text_len = text.length;
|
42 | var chars = text.split('');
|
43 | var test_line = null;
|
44 | ctx.textAlign = 'left';
|
45 | ctx.textBaseline = 'top';
|
46 | for (var i = 0; i < text_len; i++) {
|
47 | test_line = line + chars[i];
|
48 | if (ctx.measureText(test_line).width > w && i > 0) {
|
49 | ctx.fillText(line, x, y);
|
50 | line = chars[i];
|
51 | y += lineheight;
|
52 | } else {
|
53 | line = test_line;
|
54 | }
|
55 | }
|
56 | ctx.fillText(line, x, y);
|
57 | };
|
58 |
|
59 | jcanvas.text_ellipsis = function (ctx, text, x, y, w, h) {
|
60 | var center_y = y + h / 2;
|
61 | var text = jcanvas.fittingString(ctx, text, w);
|
62 | ctx.textAlign = 'left';
|
63 | ctx.textBaseline = 'middle';
|
64 | ctx.fillText(text, x, center_y, w);
|
65 | };
|
66 |
|
67 | jcanvas.fittingString = function (ctx, text, max_width) {
|
68 | var width = ctx.measureText(text).width;
|
69 | var ellipsis = '…';
|
70 | var ellipsis_width = ctx.measureText(ellipsis).width;
|
71 | if (width <= max_width || width <= ellipsis_width) {
|
72 | return text;
|
73 | } else {
|
74 | var len = text.length;
|
75 | while (width >= max_width - ellipsis_width && len-- > 0) {
|
76 | text = text.substring(0, len);
|
77 | width = ctx.measureText(text).width;
|
78 | }
|
79 | return text + ellipsis;
|
80 | }
|
81 | };
|
82 |
|
83 | jcanvas.image = function (ctx, url, x, y, w, h, r, rotation, callback) {
|
84 | var img = new Image();
|
85 | img.onload = function () {
|
86 | ctx.save();
|
87 | ctx.translate(x, y);
|
88 | ctx.save();
|
89 | ctx.beginPath();
|
90 | jcanvas.rect(ctx, 0, 0, w, h, r);
|
91 | ctx.closePath();
|
92 | ctx.clip();
|
93 | ctx.translate(w / 2, h / 2);
|
94 | ctx.rotate(rotation * Math.PI / 180);
|
95 | ctx.drawImage(img, -w / 2, -h / 2);
|
96 | ctx.restore();
|
97 | ctx.restore();
|
98 | !!callback && callback();
|
99 | }
|
100 | img.src = url;
|
101 | };
|
102 |
|
103 | jsMind.screenshot = function (jm) {
|
104 | this.jm = jm;
|
105 | this.canvas_elem = null;
|
106 | this.canvas_ctx = null;
|
107 | this._inited = false;
|
108 | };
|
109 |
|
110 | jsMind.screenshot.prototype = {
|
111 | init: function () {
|
112 | if (this._inited) { return; }
|
113 | console.log('init');
|
114 | var c = $c('canvas');
|
115 | var ctx = c.getContext('2d');
|
116 |
|
117 | this.canvas_elem = c;
|
118 | this.canvas_ctx = ctx;
|
119 | this.jm.view.e_panel.appendChild(c);
|
120 | this._inited = true;
|
121 | this.resize();
|
122 | },
|
123 |
|
124 | shoot: function (callback) {
|
125 | this.init();
|
126 | this._draw(function () {
|
127 | !!callback && callback();
|
128 | this.clean();
|
129 | }.bind(this));
|
130 | this._watermark();
|
131 | },
|
132 |
|
133 | shootDownload: function () {
|
134 | this.shoot(function () {
|
135 | this._download();
|
136 | }.bind(this));
|
137 | },
|
138 |
|
139 | shootAsDataURL: function (callback) {
|
140 | this.shoot(function () {
|
141 | !!callback && callback(this.canvas_elem.toDataURL());
|
142 | }.bind(this));
|
143 | },
|
144 |
|
145 | resize: function () {
|
146 | if (this._inited) {
|
147 | this.canvas_elem.width = this.jm.view.size.w;
|
148 | this.canvas_elem.height = this.jm.view.size.h;
|
149 | }
|
150 | },
|
151 |
|
152 | clean: function () {
|
153 | var c = this.canvas_elem;
|
154 | this.canvas_ctx.clearRect(0, 0, c.width, c.height);
|
155 | },
|
156 |
|
157 | _draw: function (callback) {
|
158 | var ctx = this.canvas_ctx;
|
159 | ctx.textAlign = 'left';
|
160 | ctx.textBaseline = 'top';
|
161 | this._draw_lines(function () {
|
162 | this._draw_nodes(callback);
|
163 | }.bind(this));
|
164 | },
|
165 |
|
166 | _watermark: function () {
|
167 | var c = this.canvas_elem;
|
168 | var ctx = this.canvas_ctx;
|
169 | ctx.textAlign = 'right';
|
170 | ctx.textBaseline = 'bottom';
|
171 | ctx.fillStyle = '#000';
|
172 | ctx.font = '11px Verdana,Arial,Helvetica,sans-serif';
|
173 | ctx.fillText('github.com/hizzgdev/jsmind', c.width - 5.5, c.height - 2.5);
|
174 | ctx.textAlign = 'left';
|
175 | ctx.fillText($w.location, 5.5, c.height - 2.5);
|
176 | },
|
177 |
|
178 | _draw_lines: function (callback) {
|
179 | this.jm.view.graph.copy_to(this.canvas_ctx, callback);
|
180 | },
|
181 |
|
182 | _draw_nodes: function (callback) {
|
183 | var nodes = this.jm.mind.nodes;
|
184 | var node;
|
185 | for (var nodeid in nodes) {
|
186 | node = nodes[nodeid];
|
187 | this._draw_node(node);
|
188 | }
|
189 |
|
190 | function check_nodes_ready() {
|
191 | console.log('check_node_ready' + new Date());
|
192 | var allOk = true;
|
193 | for (var nodeid in nodes) {
|
194 | node = nodes[nodeid];
|
195 | allOk = allOk & node.ready;
|
196 | }
|
197 |
|
198 | if (!allOk) {
|
199 | $w.setTimeout(check_nodes_ready, 200);
|
200 | } else {
|
201 | $w.setTimeout(callback, 200);
|
202 | }
|
203 | }
|
204 | check_nodes_ready();
|
205 | },
|
206 |
|
207 | _draw_node: function (node) {
|
208 | var ctx = this.canvas_ctx;
|
209 | var view_data = node._data.view;
|
210 | var node_element = view_data.element;
|
211 | var ncs = getComputedStyle(node_element);
|
212 | if (!is_visible(ncs)) {
|
213 | node.ready = true;
|
214 | return;
|
215 | }
|
216 |
|
217 | var bgcolor = css(ncs, 'background-color');
|
218 | var round_radius = parseInt(css(ncs, 'border-top-left-radius'));
|
219 | var color = css(ncs, 'color');
|
220 | var padding_left = parseInt(css(ncs, 'padding-left'));
|
221 | var padding_right = parseInt(css(ncs, 'padding-right'));
|
222 | var padding_top = parseInt(css(ncs, 'padding-top'));
|
223 | var padding_bottom = parseInt(css(ncs, 'padding-bottom'));
|
224 | var text_overflow = css(ncs, 'text-overflow');
|
225 | var font = css(ncs, 'font-style') + ' ' +
|
226 | css(ncs, 'font-variant') + ' ' +
|
227 | css(ncs, 'font-weight') + ' ' +
|
228 | css(ncs, 'font-size') + '/' + css(ncs, 'line-height') + ' ' +
|
229 | css(ncs, 'font-family');
|
230 |
|
231 | var rb = {
|
232 | x: view_data.abs_x,
|
233 | y: view_data.abs_y,
|
234 | w: view_data.width + 1,
|
235 | h: view_data.height + 1
|
236 | };
|
237 | var tb = {
|
238 | x: rb.x + padding_left,
|
239 | y: rb.y + padding_top,
|
240 | w: rb.w - padding_left - padding_right,
|
241 | h: rb.h - padding_top - padding_bottom
|
242 | };
|
243 |
|
244 | ctx.font = font;
|
245 | ctx.fillStyle = bgcolor;
|
246 | ctx.beginPath();
|
247 | jcanvas.rect(ctx, rb.x, rb.y, rb.w, rb.h, round_radius);
|
248 | ctx.closePath();
|
249 | ctx.fill();
|
250 |
|
251 | ctx.fillStyle = color;
|
252 | if ('background-image' in node.data) {
|
253 | var backgroundUrl = css(ncs, 'background-image').slice(5, -2);
|
254 | node.ready = false;
|
255 | var rotation = 0;
|
256 | if ('background-rotation' in node.data) {
|
257 | rotation = node.data['background-rotation'];
|
258 | }
|
259 | jcanvas.image(ctx, backgroundUrl, rb.x, rb.y, rb.w, rb.h, round_radius, rotation,
|
260 | function () {
|
261 | node.ready = true;
|
262 | });
|
263 | }
|
264 | if (!!node.topic) {
|
265 | if (text_overflow === 'ellipsis') {
|
266 | jcanvas.text_ellipsis(ctx, node.topic, tb.x, tb.y, tb.w, tb.h);
|
267 | } else {
|
268 | var line_height = parseInt(css(ncs, 'line-height'));
|
269 | jcanvas.text_multiline(ctx, node.topic, tb.x, tb.y, tb.w, tb.h, line_height);
|
270 | }
|
271 | }
|
272 | if (!!view_data.expander) {
|
273 | this._draw_expander(view_data.expander);
|
274 | }
|
275 | if (!('background-image' in node.data)) {
|
276 | node.ready = true;
|
277 | }
|
278 | },
|
279 |
|
280 | _draw_expander: function (expander) {
|
281 | var ctx = this.canvas_ctx;
|
282 | var ncs = getComputedStyle(expander);
|
283 | if (!is_visible(ncs)) { return; }
|
284 |
|
285 | var style_left = css(ncs, 'left');
|
286 | var style_top = css(ncs, 'top');
|
287 | var font = css(ncs, 'font');
|
288 | var left = parseInt(style_left);
|
289 | var top = parseInt(style_top);
|
290 | var is_plus = expander.innerHTML === '+';
|
291 |
|
292 | ctx.lineWidth = 1;
|
293 |
|
294 | ctx.beginPath();
|
295 | ctx.arc(left + 7, top + 7, 5, 0, Math.PI * 2, true);
|
296 | ctx.moveTo(left + 10, top + 7);
|
297 | ctx.lineTo(left + 4, top + 7);
|
298 | if (is_plus) {
|
299 | ctx.moveTo(left + 7, top + 4);
|
300 | ctx.lineTo(left + 7, top + 10);
|
301 | }
|
302 | ctx.closePath();
|
303 | ctx.stroke();
|
304 | },
|
305 |
|
306 | _download: function () {
|
307 | var c = this.canvas_elem;
|
308 | var name = this.jm.mind.name + '.png';
|
309 |
|
310 | if (navigator.msSaveBlob && (!!c.msToBlob)) {
|
311 | var blob = c.msToBlob();
|
312 | navigator.msSaveBlob(blob, name);
|
313 | } else {
|
314 | var bloburl = this.canvas_elem.toDataURL();
|
315 | var anchor = $c('a');
|
316 | if ('download' in anchor) {
|
317 | anchor.style.visibility = 'hidden';
|
318 | anchor.href = bloburl;
|
319 | anchor.download = name;
|
320 | $d.body.appendChild(anchor);
|
321 | var evt = $d.createEvent('MouseEvents');
|
322 | evt.initEvent('click', true, true);
|
323 | anchor.dispatchEvent(evt);
|
324 | $d.body.removeChild(anchor);
|
325 | } else {
|
326 | location.href = bloburl;
|
327 | }
|
328 | }
|
329 | },
|
330 |
|
331 | jm_event_handle: function (type, data) {
|
332 | if (type === jsMind.event_type.resize) {
|
333 | this.resize();
|
334 | }
|
335 | }
|
336 | };
|
337 |
|
338 | var screenshot_plugin = new jsMind.plugin('screenshot', function (jm) {
|
339 | var jss = new jsMind.screenshot(jm);
|
340 | jm.screenshot = jss;
|
341 | jm.shoot = function () {
|
342 | jss.shoot();
|
343 | };
|
344 | jm.add_event_listener(function (type, data) {
|
345 | jss.jm_event_handle.call(jss, type, data);
|
346 | });
|
347 | });
|
348 |
|
349 | jsMind.register_plugin(screenshot_plugin);
|
350 |
|
351 | })(window);
|