Mercurial > hg > NetworkVis
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); + }); + } +};