1/** 2 * mxAsyncCanvas 3 */ 4 5/** 6 * Extends mxAbstractCanvas2D 7 */ 8function mxAsyncCanvas(htmlCanvas) 9{ 10 mxAbstractCanvas2D.call(this); 11 this.htmlCanvas = htmlCanvas; 12 htmlCanvas.images = htmlCanvas.images || []; 13 htmlCanvas.subCanvas = htmlCanvas.subCanvas || []; 14}; 15 16/** 17 * Extends mxAbstractCanvas2D 18 */ 19mxUtils.extend(mxAsyncCanvas, mxAbstractCanvas2D); 20 21/** 22 * Variable: htmlCanvas 23 * 24 * The canvas instance this object is obtaining async resources for 25 */ 26mxAsyncCanvas.prototype.htmlCanvas = null; 27 28/** 29 * Variable: canvasIndex 30 * 31 * The current index into the canvas sub-canvas array being processed 32 */ 33mxAsyncCanvas.prototype.canvasIndex = 0; 34 35/** 36 * Variable: ctx 37 * 38 * Holds the current canvas context 39 */ 40mxAsyncCanvas.prototype.waitCounter = 0; 41 42/** 43 * Variable: ctx 44 * 45 * Holds the current canvas context 46 */ 47mxAsyncCanvas.prototype.onComplete = null; 48 49mxAsyncCanvas.prototype.incWaitCounter = function() 50{ 51 this.waitCounter++; 52}; 53 54mxAsyncCanvas.prototype.decWaitCounter = function() 55{ 56 this.waitCounter--; 57 58 if (this.waitCounter == 0 && this.onComplete != null) 59 { 60 this.onComplete(); 61 this.onComplete = null; 62 } 63}; 64 65mxAsyncCanvas.prototype.updateFont = function() 66{ 67 var style = ''; 68 69 if ((this.state.fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD) 70 { 71 style += 'bold '; 72 } 73 74 if ((this.state.fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC) 75 { 76 style += 'italic '; 77 } 78 79 this.ctx.font = style + this.state.fontSize + 'px ' + this.state.fontFamily; 80}; 81 82mxAsyncCanvas.prototype.rotate = function(theta, flipH, flipV, cx, cy) 83{ 84}; 85 86mxAsyncCanvas.prototype.setAlpha = function(alpha) 87{ 88 this.state.alpha = alpha; 89}; 90 91mxAsyncCanvas.prototype.setFontColor = function(value) 92{ 93 this.state.fontColor = value; 94}; 95 96mxAsyncCanvas.prototype.setFontBackgroundColor = function(value) 97{ 98 if (value == mxConstants.NONE) 99 { 100 value = null; 101 } 102 103 this.state.fontBackgroundColor = value; 104}; 105 106mxAsyncCanvas.prototype.setFontBorderColor = function(value) 107{ 108 if (value == mxConstants.NONE) 109 { 110 value = null; 111 } 112 113 this.state.fontBorderColor = value; 114}; 115 116mxAsyncCanvas.prototype.setFontSize = function(value) 117{ 118 this.state.fontSize = value; 119}; 120 121mxAsyncCanvas.prototype.setFontFamily = function(value) 122{ 123 this.state.fontFamily = value; 124}; 125 126mxAsyncCanvas.prototype.setFontStyle = function(value) 127{ 128 this.state.fontStyle = value; 129}; 130 131mxAsyncCanvas.prototype.rect = function(x, y, w, h) {}; 132 133mxAsyncCanvas.prototype.roundrect = function(x, y, w, h, dx, dy) {}; 134 135mxAsyncCanvas.prototype.ellipse = function(x, y, w, h) {}; 136 137//Redirect can be implemented via a hook 138mxAsyncCanvas.prototype.rewriteImageSource = function(src) 139{ 140 if (src.substring(0, 7) == 'http://' || src.substring(0, 8) == 'https://') 141 { 142 src = '/proxy?url=' + encodeURIComponent(src); 143 } 144 145 return src; 146}; 147 148mxAsyncCanvas.prototype.image = function(x, y, w, h, src, aspect, flipH, flipV) 149{ 150 src = this.rewriteImageSource(src); 151 var image = this.htmlCanvas.images[src]; 152 153 if (image == null) 154 { 155 var image = new Image(); 156 157 image.onload = mxUtils.bind(this, function() 158 { 159 this.decWaitCounter(); 160 }); 161 162 image.onerror = mxUtils.bind(this, function() 163 { 164 this.decWaitCounter(); 165 // TODO null the image out? this.htmlCanvas.images[src] = null; 166 }); 167 168 this.incWaitCounter(); 169 this.htmlCanvas.images[src] = image; 170 image.src = src; 171 } 172}; 173 174mxAsyncCanvas.prototype.fill = function() {}; 175 176mxAsyncCanvas.prototype.stroke = function() {}; 177 178mxAsyncCanvas.prototype.fillAndStroke = function() {}; 179 180mxAsyncCanvas.prototype.text = function(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation) 181{ 182 if (str == null || str.length == 0) 183 { 184 return; 185 } 186 187 var sc = this.state.scale; 188 189 if (format == 'html' && typeof html2canvas === 'function') 190 { 191 this.incWaitCounter(); 192 var canvasIndex = this.canvasIndex++; 193 194 html2canvas(str, 195 { 196 onrendered: mxUtils.bind(this, function(canvas) 197 { 198 this.htmlCanvas.subCanvas[canvasIndex] = canvas; 199 this.decWaitCounter(); 200 }), 201 scale: sc, 202 logging: true 203 }); 204 } 205}; 206 207mxAsyncCanvas.prototype.finish = function(handler) 208{ 209 // TODO: Check if waitCounter updates need a monitor. Question is 210 // if image load-handler can be executed in parallel leading to 211 // race conditions when updating the "shared" waitCounter. 212 if (this.waitCounter == 0) 213 { 214 handler(); 215 } 216 else 217 { 218 this.onComplete = handler; 219 } 220};