| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 | define("dojox/gfx/path", ["./_base", "dojo/_base/lang","dojo/_base/declare", "./matrix", "./shape"],   function(g, lang, declare, matrix, shapeLib){/*===== 	dojox.gfx.path = {		// summary:		//		This module contains the core graphics Path API.		//		Path command format follows the W3C SVG 1.0 Path api.	};	g = dojox.gfx;	shape.Shape = dojox.gfx.shape.Shape;  =====*/	var path = g.path = {};	var Path = declare("dojox.gfx.path.Path", shapeLib.Shape, {		// summary: a generalized path shape		constructor: function(rawNode){			// summary: a path constructor			// rawNode: Node			//		a DOM node to be used by this path object			this.shape = lang.clone(g.defaultPath);			this.segments = [];			this.tbbox = null;			this.absolute = true;			this.last = {};			this.rawNode = rawNode;			this.segmented = false;		},		// mode manipulations		setAbsoluteMode: function(mode){			// summary: sets an absolute or relative mode for path points			// mode: Boolean			//		true/false or "absolute"/"relative" to specify the mode			this._confirmSegmented();			this.absolute = typeof mode == "string" ? (mode == "absolute") : mode;			return this; // self		},		getAbsoluteMode: function(){			// summary: returns a current value of the absolute mode			this._confirmSegmented();			return this.absolute; // Boolean		},		getBoundingBox: function(){			// summary: returns the bounding box {x, y, width, height} or null			this._confirmSegmented();			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		},		_getRealBBox: function(){			// summary: returns an array of four points or null			//	four points represent four corners of the untransformed bounding box			this._confirmSegmented();			if(this.tbbox){				return this.tbbox;	// Array			}			var bbox = this.bbox, matrix = this._getRealMatrix();			this.bbox = null;			for(var i = 0, len = this.segments.length; i < len; ++i){				this._updateWithSegment(this.segments[i], matrix);			}			var t = this.bbox;			this.bbox = bbox;			this.tbbox = t ? [				{x: t.l, y: t.t},				{x: t.r, y: t.t},				{x: t.r, y: t.b},				{x: t.l, y: t.b}			] : null;			return this.tbbox;	// Array		},		getLastPosition: function(){			// summary: returns the last point in the path, or null			this._confirmSegmented();			return "x" in this.last ? this.last : null; // Object		},		_applyTransform: function(){			this.tbbox = null;			return this.inherited(arguments);		},		// segment interpretation		_updateBBox: function(x, y, m){			// summary: updates the bounding box of path with new point			// x: Number			//		an x coordinate			// y: Number			//		a y coordinate			if(m){				var t = matrix.multiplyPoint(m, x, y);				x = t.x;				y = t.y;			}			// we use {l, b, r, t} representation of a bbox			if(this.bbox && ("l" in this.bbox)){				if(this.bbox.l > x) this.bbox.l = x;				if(this.bbox.r < x) this.bbox.r = x;				if(this.bbox.t > y) this.bbox.t = y;				if(this.bbox.b < y) this.bbox.b = y;			}else{				this.bbox = {l: x, b: y, r: x, t: y};			}		},		_updateWithSegment: function(segment, matrix){			// summary: updates the bounding box of path with new segment			// segment: Object			//		a segment			var n = segment.args, l = n.length, i;			// update internal variables: bbox, absolute, last			switch(segment.action){				case "M":				case "L":				case "C":				case "S":				case "Q":				case "T":					for(i = 0; i < l; i += 2){						this._updateBBox(n[i], n[i + 1], matrix);					}					this.last.x = n[l - 2];					this.last.y = n[l - 1];					this.absolute = true;					break;				case "H":					for(i = 0; i < l; ++i){						this._updateBBox(n[i], this.last.y, matrix);					}					this.last.x = n[l - 1];					this.absolute = true;					break;				case "V":					for(i = 0; i < l; ++i){						this._updateBBox(this.last.x, n[i], matrix);					}					this.last.y = n[l - 1];					this.absolute = true;					break;				case "m":					var start = 0;					if(!("x" in this.last)){						this._updateBBox(this.last.x = n[0], this.last.y = n[1], matrix);						start = 2;					}					for(i = start; i < l; i += 2){						this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1], matrix);					}					this.absolute = false;					break;				case "l":				case "t":					for(i = 0; i < l; i += 2){						this._updateBBox(this.last.x += n[i], this.last.y += n[i + 1], matrix);					}					this.absolute = false;					break;				case "h":					for(i = 0; i < l; ++i){						this._updateBBox(this.last.x += n[i], this.last.y, matrix);					}					this.absolute = false;					break;				case "v":					for(i = 0; i < l; ++i){						this._updateBBox(this.last.x, this.last.y += n[i], matrix);					}					this.absolute = false;					break;				case "c":					for(i = 0; i < l; i += 6){						this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1], matrix);						this._updateBBox(this.last.x + n[i + 2], this.last.y + n[i + 3], matrix);						this._updateBBox(this.last.x += n[i + 4], this.last.y += n[i + 5], matrix);					}					this.absolute = false;					break;				case "s":				case "q":					for(i = 0; i < l; i += 4){						this._updateBBox(this.last.x + n[i], this.last.y + n[i + 1], matrix);						this._updateBBox(this.last.x += n[i + 2], this.last.y += n[i + 3], matrix);					}					this.absolute = false;					break;				case "A":					for(i = 0; i < l; i += 7){						this._updateBBox(n[i + 5], n[i + 6], matrix);					}					this.last.x = n[l - 2];					this.last.y = n[l - 1];					this.absolute = true;					break;				case "a":					for(i = 0; i < l; i += 7){						this._updateBBox(this.last.x += n[i + 5], this.last.y += n[i + 6], matrix);					}					this.absolute = false;					break;			}			// add an SVG path segment			var path = [segment.action];			for(i = 0; i < l; ++i){				path.push(g.formatNumber(n[i], true));			}			if(typeof this.shape.path == "string"){				this.shape.path += path.join("");			}else{				for(i = 0, l = path.length; i < l; ++i){					this.shape.path.push(path[i]);				}			}		},		// a dictionary, which maps segment type codes to a number of their arguments		_validSegments: {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0},		_pushSegment: function(action, args){			// summary: adds a segment			// action: String			//		valid SVG code for a segment's type			// args: Array			//		a list of parameters for this segment			this.tbbox = null;			var group = this._validSegments[action.toLowerCase()], segment;			if(typeof group == "number"){				if(group){					if(args.length >= group){						segment = {action: action, args: args.slice(0, args.length - args.length % group)};						this.segments.push(segment);						this._updateWithSegment(segment);					}				}else{					segment = {action: action, args: []};					this.segments.push(segment);					this._updateWithSegment(segment);				}			}		},		_collectArgs: function(array, args){			// summary: converts an array of arguments to plain numeric values			// array: Array			//		an output argument (array of numbers)			// args: Array			//		an input argument (can be values of Boolean, Number, dojox.gfx.Point, or an embedded array of them)			for(var i = 0; i < args.length; ++i){				var t = args[i];				if(typeof t == "boolean"){					array.push(t ? 1 : 0);				}else if(typeof t == "number"){					array.push(t);				}else if(t instanceof Array){					this._collectArgs(array, t);				}else if("x" in t && "y" in t){					array.push(t.x, t.y);				}			}		},		// segments		moveTo: function(){			// summary: forms a move segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "M" : "m", args);			return this; // self		},		lineTo: function(){			// summary: forms a line segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "L" : "l", args);			return this; // self		},		hLineTo: function(){			// summary: forms a horizontal line segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "H" : "h", args);			return this; // self		},		vLineTo: function(){			// summary: forms a vertical line segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "V" : "v", args);			return this; // self		},		curveTo: function(){			// summary: forms a curve segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "C" : "c", args);			return this; // self		},		smoothCurveTo: function(){			// summary: forms a smooth curve segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "S" : "s", args);			return this; // self		},		qCurveTo: function(){			// summary: forms a quadratic curve segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "Q" : "q", args);			return this; // self		},		qSmoothCurveTo: function(){			// summary: forms a quadratic smooth curve segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "T" : "t", args);			return this; // self		},		arcTo: function(){			// summary: forms an elliptic arc segment			this._confirmSegmented();			var args = [];			this._collectArgs(args, arguments);			this._pushSegment(this.absolute ? "A" : "a", args);			return this; // self		},		closePath: function(){			// summary: closes a path			this._confirmSegmented();			this._pushSegment("Z", []);			return this; // self		},		_confirmSegmented: function() {			if (!this.segmented) {				var path = this.shape.path;				// switch to non-updating version of path building				this.shape.path = [];				this._setPath(path);				// switch back to the string path				this.shape.path = this.shape.path.join("");				// become segmented				this.segmented = true;			}		},		// setShape		_setPath: function(path){			// summary: forms a path using an SVG path string			// path: String			//		an SVG path string			var p = lang.isArray(path) ? path : path.match(g.pathSvgRegExp);			this.segments = [];			this.absolute = true;			this.bbox = {};			this.last = {};			if(!p) return;			// create segments			var action = "",	// current action				args = [],		// current arguments				l = p.length;			for(var i = 0; i < l; ++i){				var t = p[i], x = parseFloat(t);				if(isNaN(x)){					if(action){						this._pushSegment(action, args);					}					args = [];					action = t;				}else{					args.push(x);				}			}			this._pushSegment(action, args);		},		setShape: function(newShape){			// summary: forms a path using a shape			// newShape: Object			//		an SVG path string or a path object (see dojox.gfx.defaultPath)			this.inherited(arguments, [typeof newShape == "string" ? {path: newShape} : newShape]);			this.segmented = false;			this.segments = [];			if(!g.lazyPathSegmentation){				this._confirmSegmented();			}			return this; // self		},		// useful constant for descendants		_2PI: Math.PI * 2	});	var TextPath = declare("dojox.gfx.path.TextPath", Path, {		// summary: a generalized TextPath shape		constructor: function(rawNode){			// summary: a TextPath shape constructor			// rawNode: Node			//		a DOM node to be used by this TextPath object			if(!("text" in this)){				this.text = lang.clone(g.defaultTextPath);			}			if(!("fontStyle" in this)){				this.fontStyle = lang.clone(g.defaultFont);			}		},		getText: function(){			// summary: returns the current text object or null			return this.text;	// Object		},		setText: function(newText){			// summary: sets a text to be drawn along the path			this.text = g.makeParameters(this.text,				typeof newText == "string" ? {text: newText} : newText);			this._setText();			return this;	// self		},		getFont: function(){			// summary: returns the current font object or null			return this.fontStyle;	// Object		},		setFont: function(newFont){			// summary: sets a font for text			this.fontStyle = typeof newFont == "string" ?				g.splitFontString(newFont) :				g.makeParameters(g.defaultFont, newFont);			this._setFont();			return this;	// self		}	});	return { // our hash of newly defined objects		Path: Path,		TextPath: TextPath	};});
 |