|
@@ -0,0 +1,349 @@
|
|
|
+/*
|
|
|
+ * Released under BSD License
|
|
|
+ * Copyright (c) 2014-2015 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 = jsMind.util.canvas;
|
|
|
+ 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,backgroundUrl,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();
|
|
|
+ }
|
|
|
+ img.src = backgroundUrl;
|
|
|
+ };
|
|
|
+
|
|
|
+ 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._watermark();
|
|
|
+ var jms = this;
|
|
|
+ this._draw(function(){
|
|
|
+ if(!!callback){
|
|
|
+ callback(jms);
|
|
|
+ }
|
|
|
+ jms.clean();
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ shootDownload: function(){
|
|
|
+ this.shoot(function(jms){
|
|
|
+ jms._download();
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ shootAsDataURL: function(callback){
|
|
|
+ this.shoot(function(jms){
|
|
|
+ callback(jms.canvas_elem.toDataURL());
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ 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();
|
|
|
+ this._draw_nodes(callback);
|
|
|
+ },
|
|
|
+
|
|
|
+ _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(){
|
|
|
+ this.jm.view.show_lines(this.canvas_ctx);
|
|
|
+ },
|
|
|
+
|
|
|
+ _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);
|