Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dojox.gfx.path"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dojox.gfx.path"] = true;
3
dojo.provide("dojox.gfx.path");
4
 
5
dojo.require("dojox.gfx.shape");
6
 
7
dojo.declare("dojox.gfx.path.Path", dojox.gfx.Shape, {
8
	// summary: a generalized path shape
9
 
10
	constructor: function(rawNode){
11
		// summary: a path constructor
12
		// rawNode: Node: a DOM node to be used by this path object
13
		this.shape = dojo.clone(dojox.gfx.defaultPath);
14
		this.segments = [];
15
		this.absolute = true;
16
		this.last = {};
17
		this.rawNode = rawNode;
18
	},
19
 
20
	// mode manipulations
21
	setAbsoluteMode: function(mode){
22
		// summary: sets an absolute or relative mode for path points
23
		// mode: Boolean: true/false or "absolute"/"relative" to specify the mode
24
		this.absolute = typeof mode == "string" ? (mode == "absolute") : mode;
25
		return this; // self
26
	},
27
	getAbsoluteMode: function(){
28
		// summary: returns a current value of the absolute mode
29
		return this.absolute; // Boolean
30
	},
31
 
32
	getBoundingBox: function(){
33
		// summary: returns the bounding box {x, y, width, height} or null
34
		return (this.bbox && ("l" in this.bbox)) ? {x: this.bbox.l, y: this.bbox.t, width: this.bbox.r - this.bbox.l, height: this.bbox.b - this.bbox.t} : null; // dojox.gfx.Rectangle
35
	},
36
 
37
	getLastPosition: function(){
38
		// summary: returns the last point in the path, or null
39
		return "x" in this.last ? this.last : null; // Object
40
	},
41
 
42
	// segment interpretation
43
	_updateBBox: function(x, y){
44
		// summary: updates the bounding box of path with new point
45
		// x: Number: an x coordinate
46
		// y: Number: a y coordinate
47
 
48
		// we use {l, b, r, t} representation of a bbox
49
		if(this.bbox && ("l" in this.bbox)){
50
			if(this.bbox.l > x) this.bbox.l = x;
51
			if(this.bbox.r < x) this.bbox.r = x;
52
			if(this.bbox.t > y) this.bbox.t = y;
53
			if(this.bbox.b < y) this.bbox.b = y;
54
		}else{
55
			this.bbox = {l: x, b: y, r: x, t: y};
56
		}
57
	},
58
	_updateWithSegment: function(segment){
59
		// summary: updates the bounding box of path with new segment
60
		// segment: Object: a segment
61
		var n = segment.args, l = n.length;
62
		// update internal variables: bbox, absolute, last
63
		switch(segment.action){
64
			case "M":
65
			case "L":
66
			case "C":
67
			case "S":
68
			case "Q":
69
			case "T":
70
				for(var i = 0; i < l; i += 2){
71
					this._updateBBox(n[i], n[i + 1]);
72
				}
73
				this.last.x = n[l - 2];
74
				this.last.y = n[l - 1];
75
				this.absolute = true;
76
				break;
77
			case "H":
78
				for(var i = 0; i < l; ++i){
79
					this._updateBBox(n[i], this.last.y);
80
				}
81
				this.last.x = n[l - 1];
82
				this.absolute = true;
83
				break;
84
			case "V":
85
				for(var i = 0; i < l; ++i){
86
					this._updateBBox(this.last.x, n[i]);
87
				}
88
				this.last.y = n[l - 1];
89
				this.absolute = true;
90
				break;
91
			case "m":
92
				var start = 0;
93
				if(!("x" in this.last)){
94
					this._updateBBox(this.last.x = n[0], this.last.y = n[1]);
95
					start = 2;
96
				}
97
				for(var i = start; i < l; i += 2){
98
					this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1]);
99
				}
100
				this.absolute = false;
101
				break;
102
			case "l":
103
			case "t":
104
				for(var i = 0; i < l; i += 2){
105
					this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1]);
106
				}
107
				this.absolute = false;
108
				break;
109
			case "h":
110
				for(var i = 0; i < l; ++i){
111
					this._updateBBox(this.last.x += n[i], this.last.y);
112
				}
113
				this.absolute = false;
114
				break;
115
			case "v":
116
				for(var i = 0; i < l; ++i){
117
					this._updateBBox(this.last.x, this.last.y += n[i]);
118
				}
119
				this.absolute = false;
120
				break;
121
			case "c":
122
				for(var i = 0; i < l; i += 6){
123
					this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1]);
124
					this._updateBBox(this.last.x + n[i + 2], this.last.y + n[i + 3]);
125
					this._updateBBox(this.last.x += n[i + 4], this.last.y += n[i + 5]);
126
				}
127
				this.absolute = false;
128
				break;
129
			case "s":
130
			case "q":
131
				for(var i = 0; i < l; i += 4){
132
					this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1]);
133
					this._updateBBox(this.last.x += n[i + 2], this.last.y += n[i + 3]);
134
				}
135
				this.absolute = false;
136
				break;
137
			case "A":
138
				for(var i = 0; i < l; i += 7){
139
					this._updateBBox(n[i + 5], n[i + 6]);
140
				}
141
				this.last.x = n[l - 2];
142
				this.last.y = n[l - 1];
143
				this.absolute = true;
144
				break;
145
			case "a":
146
				for(var i = 0; i < l; i += 7){
147
					this._updateBBox(this.last.x += n[i + 5], this.last.y += n[i + 6]);
148
				}
149
				this.absolute = false;
150
				break;
151
		}
152
		// add an SVG path segment
153
		var path = [segment.action];
154
		for(var i = 0; i < l; ++i){
155
			path.push(dojox.gfx.formatNumber(n[i], true));
156
		}
157
		if(typeof this.shape.path == "string"){
158
			this.shape.path += path.join("");
159
		}else{
160
			var l = path.length, a = this.shape.path;
161
			for(var i = 0; i < l; ++i){
162
				a.push(path[i]);
163
			}
164
		}
165
	},
166
 
167
	// a dictionary, which maps segment type codes to a number of their argemnts
168
	_validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0},
169
 
170
	_pushSegment: function(action, args){
171
		// summary: adds a segment
172
		// action: String: valid SVG code for a segment's type
173
		// args: Array: a list of parameters for this segment
174
		var group = this._validSegments[action.toLowerCase()];
175
		if(typeof group == "number"){
176
			if(group){
177
				if(args.length >= group){
178
					var segment = {action: action, args: args.slice(0, args.length - args.length % group)};
179
					this.segments.push(segment);
180
					this._updateWithSegment(segment);
181
				}
182
			}else{
183
				var segment = {action: action, args: []};
184
				this.segments.push(segment);
185
				this._updateWithSegment(segment);
186
			}
187
		}
188
	},
189
 
190
	_collectArgs: function(array, args){
191
		// summary: converts an array of arguments to plain numeric values
192
		// array: Array: an output argument (array of numbers)
193
		// args: Array: an input argument (can be values of Boolean, Number, dojox.gfx.Point, or an embedded array of them)
194
		for(var i = 0; i < args.length; ++i){
195
			var t = args[i];
196
			if(typeof t == "boolean"){
197
				array.push(t ? 1 : 0);
198
			}else if(typeof t == "number"){
199
				array.push(t);
200
			}else if(t instanceof Array){
201
				this._collectArgs(array, t);
202
			}else if("x" in t && "y" in t){
203
				array.push(t.x, t.y);
204
			}
205
		}
206
	},
207
 
208
	// segments
209
	moveTo: function(){
210
		// summary: formes a move segment
211
		var args = [];
212
		this._collectArgs(args, arguments);
213
		this._pushSegment(this.absolute ? "M" : "m", args);
214
		return this; // self
215
	},
216
	lineTo: function(){
217
		// summary: formes a line segment
218
		var args = [];
219
		this._collectArgs(args, arguments);
220
		this._pushSegment(this.absolute ? "L" : "l", args);
221
		return this; // self
222
	},
223
	hLineTo: function(){
224
		// summary: formes a horizontal line segment
225
		var args = [];
226
		this._collectArgs(args, arguments);
227
		this._pushSegment(this.absolute ? "H" : "h", args);
228
		return this; // self
229
	},
230
	vLineTo: function(){
231
		// summary: formes a vertical line segment
232
		var args = [];
233
		this._collectArgs(args, arguments);
234
		this._pushSegment(this.absolute ? "V" : "v", args);
235
		return this; // self
236
	},
237
	curveTo: function(){
238
		// summary: formes a curve segment
239
		var args = [];
240
		this._collectArgs(args, arguments);
241
		this._pushSegment(this.absolute ? "C" : "c", args);
242
		return this; // self
243
	},
244
	smoothCurveTo: function(){
245
		// summary: formes a smooth curve segment
246
		var args = [];
247
		this._collectArgs(args, arguments);
248
		this._pushSegment(this.absolute ? "S" : "s", args);
249
		return this; // self
250
	},
251
	qCurveTo: function(){
252
		// summary: formes a quadratic curve segment
253
		var args = [];
254
		this._collectArgs(args, arguments);
255
		this._pushSegment(this.absolute ? "Q" : "q", args);
256
		return this; // self
257
	},
258
	qSmoothCurveTo: function(){
259
		// summary: formes a quadratic smooth curve segment
260
		var args = [];
261
		this._collectArgs(args, arguments);
262
		this._pushSegment(this.absolute ? "T" : "t", args);
263
		return this; // self
264
	},
265
	arcTo: function(){
266
		// summary: formes an elliptic arc segment
267
		var args = [];
268
		this._collectArgs(args, arguments);
269
		this._pushSegment(this.absolute ? "A" : "a", args);
270
		return this; // self
271
	},
272
	closePath: function(){
273
		// summary: closes a path
274
		this._pushSegment("Z", []);
275
		return this; // self
276
	},
277
 
278
	// setShape
279
	_setPath: function(path){
280
		// summary: forms a path using an SVG path string
281
		// path: String: an SVG path string
282
		var p = dojo.isArray(path) ? path : path.match(dojox.gfx.pathSvgRegExp);
283
		this.segments = [];
284
		this.absolute = true;
285
		this.bbox = {};
286
		this.last = {};
287
		if(!p) return;
288
		// create segments
289
		var action = "",	// current action
290
			args = [],		// current arguments
291
			l = p.length;
292
		for(var i = 0; i < l; ++i){
293
			var t = p[i], x = parseFloat(t);
294
			if(isNaN(x)){
295
				if(action){
296
					this._pushSegment(action, args);
297
				}
298
				args = [];
299
				action = t;
300
			}else{
301
				args.push(x);
302
			}
303
		}
304
		this._pushSegment(action, args);
305
	},
306
	setShape: function(newShape){
307
		// summary: forms a path using a shape
308
		// newShape: Object: an SVG path string or a path object (see dojox.gfx.defaultPath)
309
		dojox.gfx.Shape.prototype.setShape.call(this, typeof newShape == "string" ? {path: newShape} : newShape);
310
		var path = this.shape.path;
311
		// switch to non-updating version of path building
312
		this.shape.path = [];
313
		this._setPath(path);
314
		// switch back to the string path
315
		this.shape.path = this.shape.path.join("");
316
		return this; // self
317
	},
318
 
319
	// useful constant for descendants
320
	_2PI: Math.PI * 2
321
});
322
 
323
dojo.declare("dojox.gfx.path.TextPath", dojox.gfx.path.Path, {
324
	// summary: a generalized TextPath shape
325
 
326
	constructor: function(rawNode){
327
		// summary: a TextPath shape constructor
328
		// rawNode: Node: a DOM node to be used by this TextPath object
329
		if(!("text" in this)){
330
			this.text = dojo.clone(dojox.gfx.defaultTextPath);
331
		}
332
		if(!("fontStyle" in this)){
333
			this.fontStyle = dojo.clone(dojox.gfx.defaultFont);
334
		}
335
	},
336
	setText: function(newText){
337
		// summary: sets a text to be drawn along the path
338
		this.text = dojox.gfx.makeParameters(this.text,
339
			typeof newText == "string" ? {text: newText} : newText);
340
		this._setText();
341
		return this;	// self
342
	},
343
	setFont: function(newFont){
344
		// summary: sets a font for text
345
		this.fontStyle = typeof newFont == "string" ?
346
			dojox.gfx.splitFontString(newFont) :
347
			dojox.gfx.makeParameters(dojox.gfx.defaultFont, newFont);
348
		this._setFont();
349
		return this;	// self
350
	}
351
});
352
 
353
}