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};