diff d3s_examples/python-neo4jrestclient/static/platin/js/LineOverlay/LineOverlayWidget.js @ 8:18ef6948d689

new d3s examples
author Dirk Wintergruen <dwinter@mpiwg-berlin.mpg.de>
date Thu, 01 Oct 2015 17:17:27 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/d3s_examples/python-neo4jrestclient/static/platin/js/LineOverlay/LineOverlayWidget.js	Thu Oct 01 17:17:27 2015 +0200
@@ -0,0 +1,368 @@
+/*
+* LineOverlayWidget.js
+*
+* Copyright (c) 2013, Sebastian Kruse. All rights reserved.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+* MA 02110-1301  USA
+*/
+
+//calculate angle between line and x-axis
+//credits: geometricnet (http://geometricnet.sourceforge.net/examples/directions.html)
+bearing = function(x1,y1,x2,y2) {
+	b_x = 0;
+	b_y = 1;
+	a_x = x2 - x1;
+	a_y = y2 - y1;
+	angle_rad = Math.acos((a_x*b_x+a_y*b_y)/Math.sqrt(a_x*a_x+a_y*a_y)) ;
+	angle = 360/(2*Math.PI)*angle_rad;
+	if (a_x < 0) {
+	    return 360 - angle;
+	} else {
+	    return angle;
+	}
+};
+
+/**
+ * @class LineOverlayWidget
+ * Implementation for the widget interactions of an overlay showing lines between points
+ * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
+ *
+ * @param {WidgetWrapper} core wrapper for interaction to other widgets
+ * @param {JSON} options user specified configuration that overwrites options in OverlayloaderConfig.js
+ */
+LineOverlayWidget = function (core, options) {
+
+	this.core = core;
+	this.core.setWidget(this);
+
+	this.options = (new LineOverlayConfig(options)).options;
+	
+	this.attachedMapWidgets = new Array();
+	
+	this.lineOverlay = new LineOverlay(this);
+	this.lines = [];
+	this.multiLineFeature;
+	
+	this.selected = [];
+}
+
+/**
+ * @param {Number} dataSet number of dataSet in dataSet array
+ * @param {Number} objectID number of DataObject in objects array
+ */
+
+function Line(objectStart, objectEnd ) {
+	this.objectStart = objectStart;
+	this.objectEnd = objectEnd;
+}
+
+LineOverlayWidget.prototype = {
+
+	initWidget : function() {
+		var lineOverlayWidget = this;
+		this.drawLines();
+	},
+
+	highlightChanged : function(objects) {
+		if( !GeoTemConfig.highlightEvents ){
+			return;
+		}
+		this.drawLines(GeoTemConfig.mergeObjects(objects,this.selected));
+	},
+
+	selectionChanged : function(selection) {
+		if( !GeoTemConfig.selectionEvents ){
+			return;
+		}
+		if (selection.valid())
+			this.selected = selection.objects;
+		else
+			this.selected = [];
+
+		this.drawLines(this.selected);
+	},
+
+	triggerHighlight : function(item) {
+	},
+
+	tableSelection : function() {
+	},
+
+	deselection : function() {
+	},
+
+	filtering : function() {
+	},
+
+	inverseFiltering : function() {
+	},
+
+	triggerRefining : function() {
+	},
+
+	reset : function() {
+	},
+	
+	//identical to the function in PieChartWidget
+	//here cause widgets may be used independed of each other
+	getElementData : function(dataObject, watchedColumn, selectionFunction) {
+		var columnData;
+		if (watchedColumn.indexOf("[") === -1){
+			columnData = dataObject[watchedColumn];
+			if (typeof columnData === "undefined"){
+				columnData = dataObject.tableContent[watchedColumn];
+			};
+		} else {
+			try {
+				var columnName = watchedColumn.split("[")[0];
+				var IndexAndAttribute = watchedColumn.split("[")[1];
+				if (IndexAndAttribute.indexOf("]") != -1){
+					var arrayIndex = IndexAndAttribute.split("]")[0];
+					var attribute = IndexAndAttribute.split("]")[1];
+					
+					if (typeof attribute === "undefined")
+						columnData = dataObject[columnName][arrayIndex];
+					else{
+						attribute = attribute.split(".")[1];
+						columnData = dataObject[columnName][arrayIndex][attribute];
+					}
+				}
+			} catch(e) {
+				if (typeof console !== undefined)
+					console.error(e);
+				
+				delete columnData;
+			}
+		}
+		
+		if ( (typeof columnData !== "undefined") && (typeof selectionFunction !== "undefined") )
+			columnData = selectionFunction(columnData);
+		
+		return(columnData);
+	},
+	
+	matchColumns : function(dataSet1, columnName1, dataSet2, columnName2) {
+		var lineOverlayWidget = this;
+		lineOverlayWidget.lines;
+		$(GeoTemConfig.datasets[dataSet1].objects).each(function(){
+			var object1 = this;
+			var data1 = lineOverlayWidget.getElementData(object1, columnName1);
+			//split because there could be multiple comma separated values 
+			data1 = data1.split(",");
+			
+			$(GeoTemConfig.datasets[dataSet2].objects).each(function(){
+				var object2 = this;
+				//avoid reflexive and double entries
+				if ((columnName1 === columnName2)&&(dataSet1 === dataSet2)&&(object1.index<=object2.index))
+					return;
+				var data2 = lineOverlayWidget.getElementData(object2, columnName2);
+				//split because there could be multiple comma separated values 
+				data2 = data2.split(",");
+				
+				//check if at least one pair matches
+				for(var i = 0; i < data1.length; i++ ){
+					var firstVal = data1[i];
+					if (data2.indexOf(firstVal) !== -1){
+						lineOverlayWidget.lines.push(new Line(object1, object2));
+						break;
+					}
+				}				
+			});
+		});
+	},
+	
+	getXYofObject : function(cs,dataObject){
+		//iterata over datasets
+		var x,y;
+		var found = false;
+		$(cs).each(function(){
+			//iterate over circles
+			$(this).each(function(){
+				var circle = this;
+				//iterata over objects in this circle;
+				var index = $.inArray(dataObject,circle.elements); 
+				if (index !== -1){
+					x = circle.feature.geometry.x;
+					y = circle.feature.geometry.y;
+					found = true;
+					return false;
+				}
+			});
+			//break loop
+			if (found === true)
+				return false;
+		});
+		
+		return ({x:x,y:y});
+	},
+	
+	/**
+	 * @param {DataObjects[][]} objects set of objects to limit to
+	 */
+	drawLines : function(objects) {
+		var flatObjects = [];
+		if (	(typeof objects !== "undefined") &&
+				(objects instanceof Array) &&
+				(objects.length > 0) ) {
+			$(objects).each(function(){
+				$.merge(flatObjects, this);				
+			});
+		}
+		var lineOverlayWidget = this;
+		
+		$(lineOverlayWidget.attachedMapWidgets).each(function(){
+			var mapWidget = this.mapWidget;
+			var lineLayer = this.lineLayer;
+
+			var map = mapWidget.openlayersMap;
+			var cs = mapWidget.mds.getObjectsByZoom();
+			
+			mapWidget.openlayersMap.setLayerIndex(lineLayer, 99);
+
+			lineLayer.removeAllFeatures();
+
+			var lineElements = [];
+			
+			var checkIfLineInPreset = function(){return false;};
+			if (lineOverlayWidget.options.showLines === "inbound"){
+				checkIfLineInPreset = function(objectStart,objectEnd,flatObjects){
+					return ($.inArray(objectEnd, flatObjects) === -1);
+				};
+			} else if (lineOverlayWidget.options.showLines === "outbound"){
+				checkIfLineInPreset = function(objectStart,objectEnd,flatObjects){
+					return ($.inArray(objectStart, flatObjects) === -1);
+				};
+			} else /*if (lineOverlayWidget.options.showLines === "both")*/{
+				checkIfLineInPreset = function(objectStart,objectEnd,flatObjects){
+					return (	($.inArray(objectStart, flatObjects) === -1) &&
+								($.inArray(objectEnd, flatObjects) === -1) );
+				};
+			}
+			
+			$(lineOverlayWidget.lines).each(function(){
+				var line = this;
+				
+				if ((lineOverlayWidget.options.onlyShowSelectedOrHighlighted === true) || (flatObjects.length > 0)){
+					//if objects are limited, check whether start or end are within 
+					if (checkIfLineInPreset(line.objectStart, line.objectEnd, flatObjects))
+						return;
+				}
+				//get XY-val of start Object
+				var xyStart = lineOverlayWidget.getXYofObject(cs, line.objectStart);
+				//continue if no valid XY-coords where found
+				if ( (typeof xyStart.x === "undefined") && (typeof xyStart.y === "undefined") )
+					return;
+				var xyEnd = lineOverlayWidget.getXYofObject(cs, line.objectEnd);
+				//continue if no valid XY-coords where found
+				if ( (typeof xyEnd.x === "undefined") && (typeof xyEnd.y === "undefined") )
+					return;
+
+				//do not draw 0-length lines (from same circle)
+				if ( (xyStart.x === xyEnd.x) && (xyStart.y === xyEnd.y) )
+					return;
+
+				var points = new Array(
+						   new OpenLayers.Geometry.Point(xyStart.x, xyStart.y),
+						   new OpenLayers.Geometry.Point(xyEnd.x, xyEnd.y)
+						);
+
+				var line = new OpenLayers.Geometry.LineString(points);
+
+				//Only draw each line once. Unfortunately this check is faster
+				//than drawing multiple lines.
+				var found = false;
+				$(lineElements).each(function(){
+					var checkLine = this.line;
+					if ((	(checkLine.components[0].x === line.components[0].x) &&
+							(checkLine.components[0].y === line.components[0].y) &&
+							(checkLine.components[1].x === line.components[1].x) &&
+							(checkLine.components[1].y === line.components[1].y) ) ||
+						// if lines are "directional" (arrows) the opposite one isn't the same anymore!
+						(	(lineOverlayWidget.options.showArrows === false) &&
+							(checkLine.components[0].x === line.components[1].x) &&
+							(checkLine.components[0].y === line.components[1].y) &&
+							(checkLine.components[1].x === line.components[0].x) &&
+							(checkLine.components[1].y === line.components[0].y) ) ){
+						found = true;
+						//increase width of this line
+						this.width++;
+						//and don't draw it again
+						return false;
+					}
+				});
+				
+				if (found === true)
+					return;
+
+				lineElements.push({line:line,width:1});
+			});
+
+			$(lineElements).each(function(){ 
+				var line = this.line;
+				var width = this.width;
+				
+			        // DW width becomes some times much to large, why??
+			    width = Math.min(5,width);
+			         
+				if (lineOverlayWidget.options.showArrows === true){
+					var xyStart = line.components[0];
+					var xyEnd = line.components[1];
+				    var arrowFeature = new OpenLayers.Feature.Vector(
+						new OpenLayers.Geometry.Point(xyEnd.x-((xyEnd.x-xyStart.x)*0.03), xyEnd.y-((xyEnd.y-xyStart.y)*0.03)), 
+						{
+							type: "triangle",
+							angle: bearing(xyStart.x,xyStart.y,xyEnd.x,xyEnd.y),
+							width: width+1
+						}
+					);
+					lineLayer.addFeatures(arrowFeature);
+				}
+
+				var lineFeature = new OpenLayers.Feature.Vector(line,{width:width});
+				lineLayer.addFeatures(lineFeature);
+			});
+		});
+	},
+	
+	attachMapWidget : function(mapWidget) {
+	    var styles = new OpenLayers.StyleMap({
+	        "default": {
+	            graphicName: "${type}",
+	            rotation: "${angle}",
+	            pointRadius: "${width}",
+	            strokeColor: '#0000ff', 
+	            strokeOpacity: 0.5,
+	            strokeWidth: "${width}",
+	            fillOpacity: 1
+	        }
+	    });
+	    
+		var lineOverlayWidget = this;
+		var lineLayer = new OpenLayers.Layer.Vector("Line Layer", {
+	        styleMap: styles,
+	        isBaseLayer:false
+	    });
+		mapWidget.openlayersMap.addLayer(lineLayer);
+		mapWidget.openlayersMap.setLayerIndex(lineLayer, 99);
+		this.attachedMapWidgets.push({mapWidget:mapWidget,lineLayer:lineLayer});
+		//register zoom event
+		mapWidget.openlayersMap.events.register("zoomend", lineOverlayWidget, function(){
+			this.matchColumns(0,"ident",0,"parent");
+        
+			this.drawLines(this.selected);
+		});
+	}
+};