You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							387 lines
						
					
					
						
							8.6 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							387 lines
						
					
					
						
							8.6 KiB
						
					
					
				| /* Copyright 2005-2015 Alfresco Software, Ltd. | |
|  * | |
|  * Licensed under the Apache License, Version 2.0 (the "License"); | |
|  * you may not use this file except in compliance with the License. | |
|  * You may obtain a copy of the License at | |
|  *  | |
|  *      http://www.apache.org/licenses/LICENSE-2.0 | |
|  *  | |
|  * Unless required by applicable law or agreed to in writing, software | |
|  * distributed under the License is distributed on an "AS IS" BASIS, | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
|  * See the License for the specific language governing permissions and | |
|  * limitations under the License. | |
|  */ | |
| 
 | |
| /** | |
|  * Class to generate polyline | |
|  * | |
|  * @author Dmitry Farafonov | |
|  */ | |
|   | |
| var ANCHOR_TYPE= { | |
| 	main: "main", | |
| 	middle: "middle", | |
| 	first: "first", | |
| 	last: "last" | |
| }; | |
| 
 | |
| function Anchor(uuid, type, x, y) { | |
| 	this.uuid = uuid;  | |
| 	this.x = x; | |
| 	this.y = y; | |
| 	this.type = (type == ANCHOR_TYPE.middle) ? ANCHOR_TYPE.middle : ANCHOR_TYPE.main; | |
| }; | |
| Anchor.prototype = { | |
| 	uuid: null, | |
| 	x: 0, | |
| 	y: 0, | |
| 	type: ANCHOR_TYPE.main, | |
| 	isFirst: false, | |
| 	isLast: false, | |
| 	ndex: 0, | |
| 	typeIndex: 0 | |
| }; | |
| 
 | |
| function Polyline(uuid, points, strokeWidth, paper) { | |
| 	/* Array on coordinates: | |
| 	 * points: [{x: 410, y: 110}, 1 | |
| 	 *			{x: 570, y: 110}, 1 2 | |
| 	 *			{x: 620, y: 240},   2 3 | |
| 	 *			{x: 750, y: 270},     3 4 | |
| 	 *			{x: 650, y: 370}];      4 | |
| 	 */ | |
| 	this.points = points; | |
| 	 | |
| 	/* | |
| 	 * path for graph | |
| 	 * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]] | |
| 	 */ | |
| 	this.path = []; | |
| 	 | |
| 	this.anchors = []; | |
| 	 | |
| 	if (strokeWidth) this.strokeWidth = strokeWidth; | |
| 	 | |
| 	this.paper = paper; | |
| 	 | |
| 	this.closePath = false; | |
| 	 | |
| 	this.init(); | |
| }; | |
| 
 | |
| Polyline.prototype = { | |
| 	id: null, | |
| 	points: [], | |
| 	path: [], | |
| 	anchors: [], | |
| 	strokeWidth: 1, | |
| 	radius: 1, | |
| 	showDetails: false, | |
| 	paper: null, | |
| 	element: null, | |
| 	isDefaultConditionAvailable: false, | |
| 	closePath: false, | |
| 	 | |
| 	init: function(points){ | |
| 		var linesCount = this.getLinesCount(); | |
| 		if (linesCount < 1) | |
| 			return; | |
| 			 | |
| 		this.normalizeCoordinates(); | |
| 		 | |
| 		// create anchors | |
| 		 | |
| 		this.pushAnchor(ANCHOR_TYPE.first, this.getLine(0).x1, this.getLine(0).y1); | |
| 		 | |
| 		for (var i = 1; i < linesCount; i++) | |
| 		{ | |
| 			var line1 = this.getLine(i-1); | |
| 			this.pushAnchor(ANCHOR_TYPE.main,  line1.x2, line1.y2); | |
| 		} | |
| 		 | |
| 		this.pushAnchor(ANCHOR_TYPE.last, this.getLine(linesCount-1).x2, this.getLine(linesCount-1).y2); | |
| 		 | |
| 		this.rebuildPath(); | |
| 	}, | |
| 	 | |
| 	normalizeCoordinates: function(){ | |
| 		for(var i=0; i < this.points.length; i++){ | |
| 			this.points[i].x = parseFloat(this.points[i].x); | |
| 			this.points[i].y = parseFloat(this.points[i].y); | |
| 		} | |
| 	}, | |
| 	 | |
| 	getLinesCount: function(){ | |
| 		return this.points.length-1; | |
| 	}, | |
| 	_getLine: function(i){ | |
| 	    if (this.points.length > i && this.points[i]) { | |
| 	        return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y}; | |
| 	    } else { | |
| 	        return undefined; | |
| 	    } | |
| 	}, | |
| 	getLine: function(i){ | |
| 		var line = this._getLine(i); | |
| 		if (line != undefined) { | |
| 		    line.angle = this.getLineAngle(i); | |
| 		} | |
| 		return line; | |
| 	}, | |
| 	getLineAngle: function(i){ | |
| 		var line = this._getLine(i); | |
| 		return Math.atan2(line.y2 - line.y1, line.x2 - line.x1); | |
| 	}, | |
| 	getLineLengthX: function(i){ | |
| 		var line = this.getLine(i); | |
| 		return (line.x2 - line.x1); | |
| 	}, | |
| 	getLineLengthY: function(i){ | |
| 		var line = this.getLine(i); | |
| 		return (line.y2 - line.y1); | |
| 	}, | |
| 	getLineLength: function(i){ | |
| 		return Math.sqrt(Math.pow(this.getLineLengthX(i), 2) + Math.pow(this.getLineLengthY(i), 2)); | |
| 	}, | |
| 	 | |
| 	getAnchors: function(){ | |
| 		return this.anchors; | |
| 	}, | |
| 	getAnchorsCount: function(type){ | |
| 		if (!type) | |
| 			return this.anchors.length; | |
| 		else { | |
| 			var count = 0; | |
| 			for(var i=0; i < this.getAnchorsCount(); i++){ | |
| 				var anchor = this.anchors[i]; | |
| 				if (anchor.getType() == type) { | |
| 					count++; | |
| 				} | |
| 			} | |
| 			return count; | |
| 		} | |
| 	}, | |
| 	 | |
| 	pushAnchor: function(type, x, y, index){ | |
| 		if (type == ANCHOR_TYPE.first) { | |
| 			index = 0; | |
| 			typeIndex = 0; | |
| 		} else if (type == ANCHOR_TYPE.last) { | |
| 			index = this.getAnchorsCount(); | |
| 			typeIndex = 0; | |
| 		} else if (!index) { | |
| 			index = this.anchors.length; | |
| 		} else { | |
| 			for(var i=0; i < this.getAnchorsCount(); i++){ | |
| 				var anchor = this.anchors[i]; | |
| 				if (anchor.index > index) { | |
| 					anchor.index++; | |
| 					anchor.typeIndex++; | |
| 				} | |
| 			} | |
| 		} | |
| 		 | |
| 		var anchor = new Anchor(this.id, ANCHOR_TYPE.main, x, y, index, typeIndex); | |
| 		 | |
| 		this.anchors.push(anchor); | |
| 	}, | |
| 	 | |
| 	getAnchor: function(position){ | |
| 		return this.anchors[position]; | |
| 	}, | |
| 	 | |
| 	getAnchorByType: function(type, position){ | |
| 		if (type == ANCHOR_TYPE.first) | |
| 			return this.anchors[0]; | |
| 		if (type == ANCHOR_TYPE.last) | |
| 			return this.anchors[this.getAnchorsCount()-1]; | |
| 		 | |
| 		for(var i=0; i < this.getAnchorsCount(); i++){ | |
| 			var anchor = this.anchors[i]; | |
| 			if (anchor.type == type) { | |
| 				if( position == anchor.position) | |
| 					return anchor; | |
| 			} | |
| 		} | |
| 		return null; | |
| 	}, | |
| 	 | |
| 	addNewPoint: function(position, x, y){ | |
| 		//  | |
| 		for(var i = 0; i < this.getLinesCount(); i++){ | |
| 			var line = this.getLine(i); | |
| 			if (x > line.x1 && x < line.x2 && y > line.y1 && y < line.y2) { | |
| 				this.points.splice(i+1,0,{x: x, y: y}); | |
| 				break; | |
| 			} | |
| 		} | |
| 		 | |
| 		this.rebuildPath(); | |
| 	}, | |
| 	 | |
| 	rebuildPath: function(){ | |
| 		var path = []; | |
| 		 | |
| 		for(var i = 0; i < this.getAnchorsCount(); i++){ | |
| 			var anchor = this.getAnchor(i); | |
| 			 | |
| 			var pathType = ""; | |
| 			if (i == 0) | |
| 				pathType = "M"; | |
| 			else  | |
| 				pathType = "L"; | |
| 			 | |
| 			// TODO: save previous points and calculate new path just if points are updated, and then save currents values as previous | |
| 			 | |
| 			var targetX = anchor.x, targetY = anchor.y; | |
| 			if (i>0 && i < this.getAnchorsCount()-1) { | |
| 				// get new x,y | |
| 				var cx = anchor.x, cy = anchor.y; | |
| 				 | |
| 				// pivot point of prev line | |
| 				var AO = this.getLineLength(i-1); | |
| 				if (AO < this.radius) { | |
| 					AO = this.radius; | |
| 				} | |
| 				 | |
| 				this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10)); | |
| 				 | |
| 				var ED = this.getLineLengthY(i-1) * this.radius / AO; | |
| 				var OD = this.getLineLengthX(i-1) * this.radius / AO; | |
| 					targetX = anchor.x - OD; | |
| 					targetY = anchor.y - ED; | |
| 				 | |
| 				if (AO < 2*this.radius && i>1) { | |
| 					targetX = anchor.x - this.getLineLengthX(i-1)/2; | |
| 					targetY = anchor.y - this.getLineLengthY(i-1)/2;; | |
| 				} | |
| 					 | |
| 				// pivot point of next line | |
| 				var AO = this.getLineLength(i); | |
| 				if (AO < this.radius) { | |
| 					AO = this.radius; | |
| 				} | |
| 				var ED = this.getLineLengthY(i) * this.radius / AO; | |
| 				var OD = this.getLineLengthX(i) * this.radius / AO; | |
| 					var nextSrcX = anchor.x + OD; | |
| 					var nextSrcY = anchor.y + ED; | |
| 					 | |
| 				if (AO < 2*this.radius && i<this.getAnchorsCount()-2) { | |
| 					nextSrcX = anchor.x + this.getLineLengthX(i)/2; | |
| 					nextSrcY = anchor.y + this.getLineLengthY(i)/2;; | |
| 				} | |
| 					 | |
| 				 | |
| 				var dx0 = (cx - targetX) / 3, | |
| 					dy0 = (cy - targetY) / 3, | |
| 					ax = cx - dx0, | |
| 					ay = cy - dy0, | |
| 					 | |
| 					dx1 = (cx - nextSrcX) / 3, | |
| 					dy1 = (cy - nextSrcY) / 3, | |
| 					bx = cx - dx1, | |
| 					by = cy - dy1, | |
| 					 | |
| 					zx=nextSrcX, zy=nextSrcY; | |
| 					 | |
| 			} else if (i==1 && this.getAnchorsCount() == 2){ | |
| 				var AO = this.getLineLength(i-1); | |
| 				if (AO < this.radius) { | |
| 					AO = this.radius; | |
| 				} | |
| 				this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10)); | |
| 			} | |
| 
 | |
| 			// anti smoothing | |
| 			if (this.strokeWidth%2 == 1) { | |
| 				targetX += 0.5; | |
| 				targetY += 0.5; | |
| 			} | |
| 			 | |
| 			path.push([pathType, targetX, targetY]); | |
| 			 | |
| 			if (i>0 && i < this.getAnchorsCount()-1) { | |
| 				path.push(["C", ax, ay, bx, by, zx, zy]); | |
| 			} | |
| 		} | |
| 		 | |
| 		if (this.closePath)  | |
| 		{ | |
| 			path.push(["Z"]); | |
| 		} | |
| 		 | |
| 		this.path = path; | |
| 	}, | |
| 	 | |
| 	transform: function(transformation) | |
| 	{ | |
| 		this.element.transform(transformation); | |
| 	}, | |
| 	attr: function(attrs) | |
| 	{ | |
| 		// TODO: foreach and set each | |
| 		this.element.attr(attrs); | |
| 	} | |
| }; | |
| 
 | |
| function Polygone(points, strokeWidth) { | |
| 	/* Array on coordinates: | |
| 	 * points: [{x: 410, y: 110}, 1 | |
| 	 *			{x: 570, y: 110}, 1 2 | |
| 	 *			{x: 620, y: 240},   2 3 | |
| 	 *			{x: 750, y: 270},     3 4 | |
| 	 *			{x: 650, y: 370}];      4 | |
| 	 */ | |
| 	this.points = points; | |
| 	 | |
| 	/* | |
| 	 * path for graph | |
| 	 * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]] | |
| 	 */ | |
| 	this.path = []; | |
| 	 | |
| 	this.anchors = []; | |
| 	 | |
| 	if (strokeWidth) this.strokeWidth = strokeWidth; | |
| 	 | |
| 	this.closePath = true; | |
| 	this.init(); | |
| }; | |
| 
 | |
| 
 | |
| /* | |
|  * Poligone is inherited from Poliline: draws closedPath of polyline | |
|  */ | |
| 
 | |
| var Foo = function () { }; | |
| Foo.prototype = Polyline.prototype; | |
| 
 | |
| Polygone.prototype = new Foo(); | |
| 
 | |
| Polygone.prototype.rebuildPath = function(){ | |
| 	var path = []; | |
| 	for(var i = 0; i < this.getAnchorsCount(); i++){ | |
| 		var anchor = this.getAnchor(i); | |
| 		 | |
| 		var pathType = ""; | |
| 		if (i == 0) | |
| 			pathType = "M"; | |
| 		else  | |
| 			pathType = "L"; | |
| 		 | |
| 		var targetX = anchor.x, targetY = anchor.y; | |
| 		 | |
| 		// anti smoothing | |
| 		if (this.strokeWidth%2 == 1) { | |
| 			targetX += 0.5; | |
| 			targetY += 0.5; | |
| 		} | |
| 		 | |
| 		path.push([pathType, targetX, targetY]);	 | |
| 	} | |
| 	if (this.closePath) | |
| 		path.push(["Z"]); | |
| 	 | |
| 	this.path = path; | |
| };
 | |
| 
 |