Mercurial > hg > mpiwg_geobrowser
comparison lib/GeoTemCo/js/LineOverlay/LineOverlayWidget.js @ 0:b57c7821382f
initial
author | Dirk Wintergruen <dwinter@mpiwg-berlin.mpg.de> |
---|---|
date | Thu, 28 May 2015 10:28:12 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:b57c7821382f |
---|---|
1 /* | |
2 * LineOverlayWidget.js | |
3 * | |
4 * Copyright (c) 2013, Sebastian Kruse. All rights reserved. | |
5 * | |
6 * This library is free software; you can redistribute it and/or | |
7 * modify it under the terms of the GNU Lesser General Public | |
8 * License as published by the Free Software Foundation; either | |
9 * version 3 of the License, or (at your option) any later version. | |
10 * | |
11 * This library is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * Lesser General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU Lesser General Public | |
17 * License along with this library; if not, write to the Free Software | |
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
19 * MA 02110-1301 USA | |
20 */ | |
21 | |
22 //calculate angle between line and x-axis | |
23 //credits: geometricnet (http://geometricnet.sourceforge.net/examples/directions.html) | |
24 bearing = function(x1,y1,x2,y2) { | |
25 b_x = 0; | |
26 b_y = 1; | |
27 a_x = x2 - x1; | |
28 a_y = y2 - y1; | |
29 angle_rad = Math.acos((a_x*b_x+a_y*b_y)/Math.sqrt(a_x*a_x+a_y*a_y)) ; | |
30 angle = 360/(2*Math.PI)*angle_rad; | |
31 if (a_x < 0) { | |
32 return 360 - angle; | |
33 } else { | |
34 return angle; | |
35 } | |
36 }; | |
37 | |
38 /** | |
39 * @class LineOverlayWidget | |
40 * Implementation for the widget interactions of an overlay showing lines between points | |
41 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de) | |
42 * | |
43 * @param {WidgetWrapper} core wrapper for interaction to other widgets | |
44 * @param {JSON} options user specified configuration that overwrites options in OverlayloaderConfig.js | |
45 */ | |
46 LineOverlayWidget = function (core, options) { | |
47 | |
48 this.core = core; | |
49 this.core.setWidget(this); | |
50 | |
51 this.options = (new LineOverlayConfig(options)).options; | |
52 | |
53 this.attachedMapWidgets = new Array(); | |
54 | |
55 this.lineOverlay = new LineOverlay(this); | |
56 this.lines = []; | |
57 this.multiLineFeature; | |
58 | |
59 this.selected = []; | |
60 } | |
61 | |
62 /** | |
63 * @param {Number} dataSet number of dataSet in dataSet array | |
64 * @param {Number} objectID number of DataObject in objects array | |
65 */ | |
66 | |
67 function Line(objectStart, objectEnd ) { | |
68 this.objectStart = objectStart; | |
69 this.objectEnd = objectEnd; | |
70 } | |
71 | |
72 LineOverlayWidget.prototype = { | |
73 | |
74 initWidget : function() { | |
75 var lineOverlayWidget = this; | |
76 this.drawLines(); | |
77 }, | |
78 | |
79 highlightChanged : function(objects) { | |
80 if( !GeoTemConfig.highlightEvents ){ | |
81 return; | |
82 } | |
83 this.drawLines(GeoTemConfig.mergeObjects(objects,this.selected)); | |
84 }, | |
85 | |
86 selectionChanged : function(selection) { | |
87 if( !GeoTemConfig.selectionEvents ){ | |
88 return; | |
89 } | |
90 if (selection.valid()) | |
91 this.selected = selection.objects; | |
92 else | |
93 this.selected = []; | |
94 | |
95 this.drawLines(this.selected); | |
96 }, | |
97 | |
98 triggerHighlight : function(item) { | |
99 }, | |
100 | |
101 tableSelection : function() { | |
102 }, | |
103 | |
104 deselection : function() { | |
105 }, | |
106 | |
107 filtering : function() { | |
108 }, | |
109 | |
110 inverseFiltering : function() { | |
111 }, | |
112 | |
113 triggerRefining : function() { | |
114 }, | |
115 | |
116 reset : function() { | |
117 }, | |
118 | |
119 //identical to the function in PieChartWidget | |
120 //here cause widgets may be used independed of each other | |
121 getElementData : function(dataObject, watchedColumn, selectionFunction) { | |
122 var columnData; | |
123 if (watchedColumn.indexOf("[") === -1){ | |
124 columnData = dataObject[watchedColumn]; | |
125 if (typeof columnData === "undefined"){ | |
126 columnData = dataObject.tableContent[watchedColumn]; | |
127 }; | |
128 } else { | |
129 try { | |
130 var columnName = watchedColumn.split("[")[0]; | |
131 var IndexAndAttribute = watchedColumn.split("[")[1]; | |
132 if (IndexAndAttribute.indexOf("]") != -1){ | |
133 var arrayIndex = IndexAndAttribute.split("]")[0]; | |
134 var attribute = IndexAndAttribute.split("]")[1]; | |
135 | |
136 if (typeof attribute === "undefined") | |
137 columnData = dataObject[columnName][arrayIndex]; | |
138 else{ | |
139 attribute = attribute.split(".")[1]; | |
140 columnData = dataObject[columnName][arrayIndex][attribute]; | |
141 } | |
142 } | |
143 } catch(e) { | |
144 if (typeof console !== undefined) | |
145 console.error(e); | |
146 | |
147 delete columnData; | |
148 } | |
149 } | |
150 | |
151 if ( (typeof columnData !== "undefined") && (typeof selectionFunction !== "undefined") ) | |
152 columnData = selectionFunction(columnData); | |
153 | |
154 return(columnData); | |
155 }, | |
156 | |
157 matchColumns : function(dataSet1, columnName1, dataSet2, columnName2) { | |
158 var lineOverlayWidget = this; | |
159 lineOverlayWidget.lines; | |
160 $(GeoTemConfig.datasets[dataSet1].objects).each(function(){ | |
161 var object1 = this; | |
162 var data1 = lineOverlayWidget.getElementData(object1, columnName1); | |
163 //split because there could be multiple comma separated values | |
164 data1 = data1.split(","); | |
165 | |
166 $(GeoTemConfig.datasets[dataSet2].objects).each(function(){ | |
167 var object2 = this; | |
168 //avoid reflexive and double entries | |
169 if ((columnName1 === columnName2)&&(dataSet1 === dataSet2)&&(object1.index<=object2.index)) | |
170 return; | |
171 var data2 = lineOverlayWidget.getElementData(object2, columnName2); | |
172 //split because there could be multiple comma separated values | |
173 data2 = data2.split(","); | |
174 | |
175 //check if at least one pair matches | |
176 for(var i = 0; i < data1.length; i++ ){ | |
177 var firstVal = data1[i]; | |
178 if (data2.indexOf(firstVal) !== -1){ | |
179 lineOverlayWidget.lines.push(new Line(object1, object2)); | |
180 break; | |
181 } | |
182 } | |
183 }); | |
184 }); | |
185 }, | |
186 | |
187 getXYofObject : function(cs,dataObject){ | |
188 //iterata over datasets | |
189 var x,y; | |
190 var found = false; | |
191 $(cs).each(function(){ | |
192 //iterate over circles | |
193 $(this).each(function(){ | |
194 var circle = this; | |
195 //iterata over objects in this circle; | |
196 var index = $.inArray(dataObject,circle.elements); | |
197 if (index !== -1){ | |
198 x = circle.feature.geometry.x; | |
199 y = circle.feature.geometry.y; | |
200 found = true; | |
201 return false; | |
202 } | |
203 }); | |
204 //break loop | |
205 if (found === true) | |
206 return false; | |
207 }); | |
208 | |
209 return ({x:x,y:y}); | |
210 }, | |
211 | |
212 /** | |
213 * @param {DataObjects[][]} objects set of objects to limit to | |
214 */ | |
215 drawLines : function(objects) { | |
216 var flatObjects = []; | |
217 if ( (typeof objects !== "undefined") && | |
218 (objects instanceof Array) && | |
219 (objects.length > 0) ) { | |
220 $(objects).each(function(){ | |
221 $.merge(flatObjects, this); | |
222 }); | |
223 } | |
224 var lineOverlayWidget = this; | |
225 | |
226 $(lineOverlayWidget.attachedMapWidgets).each(function(){ | |
227 var mapWidget = this.mapWidget; | |
228 var lineLayer = this.lineLayer; | |
229 | |
230 var map = mapWidget.openlayersMap; | |
231 var cs = mapWidget.mds.getObjectsByZoom(); | |
232 | |
233 mapWidget.openlayersMap.setLayerIndex(lineLayer, 99); | |
234 | |
235 lineLayer.removeAllFeatures(); | |
236 | |
237 var lineElements = []; | |
238 | |
239 var checkIfLineInPreset = function(){return false;}; | |
240 if (lineOverlayWidget.options.showLines === "inbound"){ | |
241 checkIfLineInPreset = function(objectStart,objectEnd,flatObjects){ | |
242 return ($.inArray(objectEnd, flatObjects) === -1); | |
243 }; | |
244 } else if (lineOverlayWidget.options.showLines === "outbound"){ | |
245 checkIfLineInPreset = function(objectStart,objectEnd,flatObjects){ | |
246 return ($.inArray(objectStart, flatObjects) === -1); | |
247 }; | |
248 } else /*if (lineOverlayWidget.options.showLines === "both")*/{ | |
249 checkIfLineInPreset = function(objectStart,objectEnd,flatObjects){ | |
250 return ( ($.inArray(objectStart, flatObjects) === -1) && | |
251 ($.inArray(objectEnd, flatObjects) === -1) ); | |
252 }; | |
253 } | |
254 | |
255 $(lineOverlayWidget.lines).each(function(){ | |
256 var line = this; | |
257 | |
258 if ((lineOverlayWidget.options.onlyShowSelectedOrHighlighted === true) || (flatObjects.length > 0)){ | |
259 //if objects are limited, check whether start or end are within | |
260 if (checkIfLineInPreset(line.objectStart, line.objectEnd, flatObjects)) | |
261 return; | |
262 } | |
263 //get XY-val of start Object | |
264 var xyStart = lineOverlayWidget.getXYofObject(cs, line.objectStart); | |
265 //continue if no valid XY-coords where found | |
266 if ( (typeof xyStart.x === "undefined") && (typeof xyStart.y === "undefined") ) | |
267 return; | |
268 var xyEnd = lineOverlayWidget.getXYofObject(cs, line.objectEnd); | |
269 //continue if no valid XY-coords where found | |
270 if ( (typeof xyEnd.x === "undefined") && (typeof xyEnd.y === "undefined") ) | |
271 return; | |
272 | |
273 //do not draw 0-length lines (from same circle) | |
274 if ( (xyStart.x === xyEnd.x) && (xyStart.y === xyEnd.y) ) | |
275 return; | |
276 | |
277 var points = new Array( | |
278 new OpenLayers.Geometry.Point(xyStart.x, xyStart.y), | |
279 new OpenLayers.Geometry.Point(xyEnd.x, xyEnd.y) | |
280 ); | |
281 | |
282 var line = new OpenLayers.Geometry.LineString(points); | |
283 | |
284 //Only draw each line once. Unfortunately this check is faster | |
285 //than drawing multiple lines. | |
286 var found = false; | |
287 $(lineElements).each(function(){ | |
288 var checkLine = this.line; | |
289 if (( (checkLine.components[0].x === line.components[0].x) && | |
290 (checkLine.components[0].y === line.components[0].y) && | |
291 (checkLine.components[1].x === line.components[1].x) && | |
292 (checkLine.components[1].y === line.components[1].y) ) || | |
293 // if lines are "directional" (arrows) the opposite one isn't the same anymore! | |
294 ( (lineOverlayWidget.options.showArrows === false) && | |
295 (checkLine.components[0].x === line.components[1].x) && | |
296 (checkLine.components[0].y === line.components[1].y) && | |
297 (checkLine.components[1].x === line.components[0].x) && | |
298 (checkLine.components[1].y === line.components[0].y) ) ){ | |
299 found = true; | |
300 //increase width of this line | |
301 this.width++; | |
302 //and don't draw it again | |
303 return false; | |
304 } | |
305 }); | |
306 | |
307 if (found === true) | |
308 return; | |
309 | |
310 lineElements.push({line:line,width:1}); | |
311 }); | |
312 | |
313 $(lineElements).each(function(){ | |
314 var line = this.line; | |
315 var width = this.width; | |
316 | |
317 if (lineOverlayWidget.options.showArrows === true){ | |
318 var xyStart = line.components[0]; | |
319 var xyEnd = line.components[1]; | |
320 var arrowFeature = new OpenLayers.Feature.Vector( | |
321 new OpenLayers.Geometry.Point(xyEnd.x-((xyEnd.x-xyStart.x)*0.03), xyEnd.y-((xyEnd.y-xyStart.y)*0.03)), | |
322 { | |
323 type: "triangle", | |
324 angle: bearing(xyStart.x,xyStart.y,xyEnd.x,xyEnd.y), | |
325 width: width+1 | |
326 } | |
327 ); | |
328 lineLayer.addFeatures(arrowFeature); | |
329 } | |
330 | |
331 var lineFeature = new OpenLayers.Feature.Vector(line,{width:width}); | |
332 lineLayer.addFeatures(lineFeature); | |
333 }); | |
334 }); | |
335 }, | |
336 | |
337 attachMapWidget : function(mapWidget) { | |
338 var styles = new OpenLayers.StyleMap({ | |
339 "default": { | |
340 graphicName: "${type}", | |
341 rotation: "${angle}", | |
342 pointRadius: "${width}", | |
343 strokeColor: '#0000ff', | |
344 strokeOpacity: 0.5, | |
345 strokeWidth: "${width}", | |
346 fillOpacity: 1 | |
347 } | |
348 }); | |
349 | |
350 var lineOverlayWidget = this; | |
351 var lineLayer = new OpenLayers.Layer.Vector("Line Layer", { | |
352 styleMap: styles, | |
353 isBaseLayer:false | |
354 }); | |
355 mapWidget.openlayersMap.addLayer(lineLayer); | |
356 mapWidget.openlayersMap.setLayerIndex(lineLayer, 99); | |
357 this.attachedMapWidgets.push({mapWidget:mapWidget,lineLayer:lineLayer}); | |
358 //register zoom event | |
359 mapWidget.openlayersMap.events.register("zoomend", lineOverlayWidget, function(){ | |
360 this.drawLines(this.selected); | |
361 }); | |
362 } | |
363 }; |