[Mapbender-commits] r10113 - trunk/mapbender/lib
svn_mapbender at osgeo.org
svn_mapbender at osgeo.org
Wed Apr 24 02:21:06 PDT 2019
Author: armin11
Date: 2019-04-24 02:21:06 -0700 (Wed, 24 Apr 2019)
New Revision: 10113
Modified:
trunk/mapbender/lib/mb.ui.displayKmlFeatures.js
Log:
New option to integrate wms getfeature info and selection of digitized objects - thanx to federal german state hesse ;-)
Modified: trunk/mapbender/lib/mb.ui.displayKmlFeatures.js
===================================================================
--- trunk/mapbender/lib/mb.ui.displayKmlFeatures.js 2019-04-24 05:54:16 UTC (rev 10112)
+++ trunk/mapbender/lib/mb.ui.displayKmlFeatures.js 2019-04-24 09:21:06 UTC (rev 10113)
@@ -57,54 +57,39 @@
self.render();
});
- this.element.bind('click', function(e) {
- if (self.lastWasBox) {
- self.lastWasBox = false;
- return;
- }
- var map = self.element.mapbender();
- var pos = map.getMousePosition(e);
- var clickPoint = map.convertPixelToReal(new Point(pos.x, pos.y));
- var wgspt = Proj4js.transform(self.targetProj, self.wgs84, {
- x: clickPoint.x,
- y: clickPoint.y
- });
- var res = map.getScale() / mb_resolution / 100;
+ var delta = 2;
+ var lastX, lastY;
+ var box;
+ this.element.bind('mousedown', function(e) {
if (!self.queriedLayer) return;
- var matchedIds = self.findFeatures(pos);
-
- self.updateSelectedFeatures(matchedIds, e.ctrlKey);
- });
-
- var boxfun;
-
- this.element.bind('mousedown', boxfun = function(e) {
- if (!self.queriedLayer) return;
- var box = new Mapbender.Box({
+ lastX = e.clientX;
+ lastY = e.clientY;
+ box = new Mapbender.Box({
target: 'mapframe1'
});
box.start(e);
$('#mapframe1').css("cursor", "crosshair")
- .mouseup(function(e) {
- box.stop(e, function(extent) {
- if (typeof extent === "undefined") {
- return;
- }
+ });
+
+ $('#mapframe1').mouseup(function(e) {
+ if (!self.queriedLayer) return;
+ var matchedIds;
+ var extent = box.stop(e);
+ $('#mapframe1').css("cursor", "default");
+ if (Math.abs(lastX - e.clientX) <= delta && Math.abs(lastY - e.clientY) <= delta) {
+ // click
+ matchedIds = self.findFeaturesAtClick(e);
+ } else {
+ // drag
+ if (typeof extent === "undefined") {
+ return;
+ }
- var matchedIds = self.findFeatures(extent);
- self.updateSelectedFeatures(matchedIds, e.ctrlKey);
- self.lastWasBox = true;
-
- $('#mapframe1')
- .css("cursor", "default")
- .unbind("mousedown")
- .unbind("mouseup")
- .unbind("mousemove")
- .bind('mousedown', boxfun);
- });
- return false;
- });
+ matchedIds = self.findFeaturesInExtent(extent);
+ }
+ self.updateSelectedFeatures(matchedIds, e.ctrlKey);
+ return false;
});
self.element.bind('kml:loaded', function(event, obj) {
@@ -149,95 +134,90 @@
self._load(o.url);
}
},
-
- findFeatures: function(posOrBox) {
- var matchedIds = [];
-
- var self = this;
- var map = self.element.mapbender();
- var ispoint;
- var clickPoint, wgspt, clickBox, min, max;
- if (posOrBox.x) {
- clickPoint = map.convertPixelToReal(new Point(posOrBox.x, posOrBox.y));
- wgspt = Proj4js.transform(self.targetProj, self.wgs84, {
- x: clickPoint.x,
- y: clickPoint.y
- });
- ispoint = true;
+
+ /**
+ * Check if the point lies inside the box.
+ * @param {type} point
+ * @param {type} box
+ * @returns {Boolean}
+ */
+ pointInBox: function (point, box) {
+ if (point.x >= box.minx && point.x <= box.maxx
+ && point.y >= box.miny && point.y <= box.maxy) {
+ return true;
} else {
- clickBox = posOrBox;
- min = Proj4js.transform(self.targetProj, self.wgs84, {
- x: clickBox.minx,
- y: clickBox.miny
- });
- max = Proj4js.transform(self.targetProj, self.wgs84, {
- x: clickBox.maxx,
- y: clickBox.maxy
- });
- ispoint = false;
+ return false;
}
- var res = map.getScale() / mb_resolution / 100;
+ },
- $.each(self._kmls, function(_, itm) {
- $.each(itm.data.features, function(k, v) {
- if (ispoint) {
- //console.log( "isPoint" );
- self.matchFeatureToPoint(v, clickPoint, matchedIds, res, itm, wgspt, k);
- } else {
- self.matchFeatureToBox(v, {
- min: min,
- max: max
- }, matchedIds, itm, k);
- }
- });
- });
- return matchedIds;
+ /**
+ * Checks if value x is between y1 and y2. It works also if y2 < y1.
+ * @param {type} x
+ * @param {type} y1
+ * @param {type} y2
+ * @returns {Number}
+ */
+ valueIsBetween: function (x, y1, y2) {
+ return (y1 - x) * (y2 - x) <= 0;
},
+ /**
+ * calculates the Y value of line for a given X.
+ * @param {type} line
+ * @param {type} y
+ * @returns {Number}
+ */
+ lineYAtX: function (line, x) {
+ return line.y2 + (x - line.x2) * (line.y1 - line.y2) / (line.x1 - line.x2)
+ },
- inBox: function(minx, miny, maxx, maxy, selectBoxMinx, selectBoxMaxx, selectBoxMiny, selectBoxMaxy) {
+ /**
+ * calculates the X value of line for a given Y.
+ * @param {type} line
+ * @param {type} y
+ * @returns {Number}
+ */
+ lineXAtY: function (line, y) {
+ return line.x2 + (y - line.y2) * (line.x1 - line.x2) / (line.y1 - line.y2)
+ },
- // ############## proof the min-point ##################
- // proof hit on the x-axis
- if ( ( minx >= selectBoxMinx && minx <= selectBoxMaxx ) ) {
- // if x hit, proof y
- if ( ( miny >= selectBoxMiny && miny <= selectBoxMaxy ) ) {
- return true;
- }
+ /**
+ * First checks if line is completely contained inside of the box. If not it checks
+ * if one of the sides of the box intersects with the line.
+ * @param {type} line
+ * @param {type} box
+ * @returns {Boolean}
+ */
+ lineIntersectsBox: function (line, box) {
+ if (this.pointInBox({ x: line.x1, y: line.y1 }, box)
+ || this.pointInBox({ x: line.x1, y: line.y1 }, box)) {
+ return true;
}
- // proof hit on the y-axis
- if ( ( miny >= selectBoxMiny && miny <= selectBoxMaxy ) ) {
- // if y hit, proof x
- if ( ( minx >= selectBoxMinx && minx <= selectBoxMaxx ) ) {
+
+ if (this.valueIsBetween(box.minx, line.x1, line.x2)) {
+ var y = this.lineYAtX(line, box.minx);
+ if (y >= box.miny && y <= box.maxy) {
return true;
}
}
- // ############## proof the max-point ##################
- if ( ( maxx >= selectBoxMinx && maxx <= selectBoxMaxx ) ) {
- // if x hit, proof y
- if ( ( maxy >= selectBoxMiny && maxy <= selectBoxMaxy ) ) {
- return true;
- }
- }
- if ( ( maxy >= selectBoxMiny && maxy <= selectBoxMaxy ) ) {
- // if y hit, proof x
- if ( ( maxx >= selectBoxMinx && maxx <= selectBoxMaxx ) ) {
+ if (this.valueIsBetween(box.maxx, line.x1, line.x2)) {
+ var y = this.lineYAtX(line, box.maxx);
+ if (y >= box.miny && y <= box.maxy) {
return true;
}
}
- // ############## proof if selectbox contains the feature geometry ##################
- // proof on x-axis
- if ( minx >= selectBoxMinx && minx <= selectBoxMaxx && maxx >= selectBoxMinx && maxx <= selectBoxMaxx ) {
- if ( miny <= selectBoxMiny && maxy >= selectBoxMaxy ) {
+ if (this.valueIsBetween(box.miny, line.y1, line.y2)) {
+ var x = this.lineXAtY(line, box.miny);
+ if (x >= box.minx && x <= box.maxx) {
return true;
}
}
- // proof on y-axis
- if ( miny >= selectBoxMiny && miny <= selectBoxMaxy && maxy >= selectBoxMiny && maxx <= selectBoxMaxy ) {
- if ( minx <= selectBoxMinx && maxx >= selectBoxMaxx ) {
+ if (this.valueIsBetween(box.maxy, line.y1, line.y2)) {
+ var x = this.lineXAtY(line, box.maxy);
+ if (x >= box.minx && x <= box.maxx) {
return true;
}
}
@@ -244,92 +224,209 @@
return false;
},
+
+ getLines: function (points, connect) {
+ lines = [];
+ for (var i = 0; i < points.length - 1; i ++) {
+ lines.push({
+ x1: points[i][0],
+ y1: points[i][1],
+ x2: points[i + 1][0],
+ y2: points[i + 1][1]
+ });
+ }
+ if (connect) {
+ lines.push({
+ x1: points[points.length - 1][0],
+ y1: points[points.length - 1][1],
+ x2: points[0][0],
+ y2: points[0][1]
+ })
+ }
+ return lines;
+ },
+
+ lineStringIntersectsBox: function (lineStringPoints, box) {
+ var self = this;
+ return this.getLines(lineStringPoints).some(function (line) {
+ return self.lineIntersectsBox(line, box);
+ });
+ },
- pointInBox: function(pointX, pointY, selectBoxMinx, selectBoxMaxx, selectBoxMiny, selectBoxMaxy) {
+ /**
+ * Checks whether a polygon intersects a box.
+ * On the one hand it checks if any of the lines on the polygon ring intersect
+ * with the box and on the other hand it checks how many times a ray cast outwards
+ * from the middle of the box intersects with one of the lines. If it intersects
+ * an odd number of times it lays inside the polygon.
+ * @param {type} polygon
+ * @param {type} box
+ * @returns {Boolean}
+ */
+ polygonIntersectsBox: function (polygonRings, box) {
+ var rayPoint = {
+ x: box.minx + (box.maxx - box.minx) / 2,
+ y: box.miny + (box.maxy - box.miny) / 2
+ };
+ var rayIntersections = 0;
- if ( ( pointX >= selectBoxMinx && pointX <= selectBoxMaxx ) && ( pointY >= selectBoxMiny && pointY <= selectBoxMaxy )) {
+ var self = this;
+ var lines = polygonRings.reduce(function (lines, ring) {
+ Array.prototype.push.apply(lines, self.getLines(ring, true));
+ return lines;
+ }, [])
+
+ for (var i = 0; i < lines.length; i++) {
+ if (this.lineIntersectsBox(lines[i], box)) {
+ return true;
+ }
+ if (this.valueIsBetween(rayPoint.y, lines[i].y1, lines[i].y2)) {
+ var x = this.lineXAtY(lines[i], rayPoint.y);
+ if (x >= rayPoint.x) {
+ rayIntersections++;
+ }
+ }
+ }
+
+ if (rayIntersections % 2 === 1) {
return true;
+ } else {
+ return false;
}
},
-
- matchFeatureToPoint: function(feat, clickPoint, matchedIds, res, itm, wgspt, idx) {
- //console.log( "point" );
- if (feat.geometry.type.match(/point/i)) {
- var pt = Proj4js.transform(this.wgs84, this.targetProj, {
- x: feat.geometry.coordinates[0],
- y: feat.geometry.coordinates[1]
- });
- var minx = pt.x - 20 * res;
- var miny = pt.y - 20 * res;
- var maxx = minx + 40 * res;
- var maxy = miny + 40 * res;
- if (minx < clickPoint.x && maxx > clickPoint.x && miny < clickPoint.y && maxy > clickPoint.y) {
- matchedIds.push({
- url: itm.url,
- id: idx
- });
- }
+
+ boxInBox: function (boxA, boxB) {
+ return this.pointInBox({ x: boxA.minx, y: boxA.miny }, boxB) &&
+ this.pointInBox({ x: boxA.maxx, y: boxA.maxy }, boxB);
+ },
+
+
+ /**
+ * Checks whether the geometry of the feature intersects with the box
+ * @param {type} feature
+ * @param {type} box
+ * @returns {Boolean}
+ */
+ featureIntersectsBox: function (feature, box) {
+ var geometryType = feature.geometry.type.toLowerCase();
+ switch (geometryType) {
+ case 'point':
+ return this.pointInBox({
+ x: feature.geometry.coordinates[0],
+ y: feature.geometry.coordinates[1]
+ }, box);
+ case 'linestring':
+ return this.lineStringIntersectsBox(feature.geometry.coordinates, box);
+ case 'polygon':
+ return this.polygonIntersectsBox(feature.geometry.coordinates, box);
+ default:
+ throw new Error('feature geometry type not supported');
+ }
+ },
+
+ featureInBox: function (feature, box) {
+ if (feature.geometry.type.toLowerCase() === 'point') {
+ return this.pointInBox({
+ x: feature.geometry.coordinates[0],
+ y: feature.geometry.coordinates[1]
+ }, box);
} else {
- var box = this.getBbox(feat);
- if (this.inBox(box[0], box[1], box[2], box[3], wgspt.x, wgspt.y)) {
- matchedIds.push({
- url: itm.url,
- id: idx
- });
+ var arrayBox = this.getBbox(feature);
+ return this.boxInBox({
+ minx: arrayBox[0],
+ miny: arrayBox[1],
+ maxx: arrayBox[2],
+ maxy: arrayBox[3]
+ }, box);
+ }
+ },
+
+
+
+ /**
+ * Finds all features that intersect with a buffer around a point or a given box.
+ * @param {type} posOrBox
+ * @returns {Array|displayFeatures.findIntersectingFeatures.ids}
+ */
+ findFeaturesAtClick: function (e) {
+ var map = this.element.mapbender();
+ var pos = map.getMousePosition(e);
+
+ var min = {
+ x: pos.x - 20,
+ y: pos.y + 20 // screen y is in opposite direction of map y
+ };
+ var max = {
+ x: pos.x + 20,
+ y: pos.y - 20
+ };
+
+ min = map.convertPixelToReal(min);
+ max = map.convertPixelToReal(max);
+
+ min = Proj4js.transform(this.targetProj, this.wgs84, min);
+ max = Proj4js.transform(this.targetProj, this.wgs84, max);
+
+ var box = {
+ minx: min.x,
+ miny: min.y,
+ maxx: max.x,
+ maxy: max.y
+ };
+
+ var self = this;
+ var matches = [];
+ for (var kmlId in this._kmls) {
+ if (this._kmls.hasOwnProperty(kmlId)) {
+ var kml = this._kmls[kmlId];
+ matches = kml.data.features.reduce(function (matches, feature, index) {
+ if (self.featureIntersectsBox(feature, box)) {
+ matches.push({
+ url: kml.url,
+ id: index
+ });
+ }
+ return matches;
+ }, matches);
}
}
+ return matches;
},
- matchFeatureToBox: function(feat, wgsbox, matchedIds, itm, idx) {
- if (feat.geometry.type.match(/point/i)) {
- //console.log( feat.geometry );
- if (this.pointInBox(feat.geometry.coordinates[0], feat.geometry.coordinates[1], wgsbox.min.x, wgsbox.max.x, wgsbox.min.y, wgsbox.max.y)) {
- matchedIds.push({
- url: itm.url,
- id: idx
- });
+ findFeaturesInExtent: function(extent) {
+ var min = Proj4js.transform(this.targetProj, this.wgs84, {
+ x: extent.minx,
+ y: extent.miny
+ });
+ var max = Proj4js.transform(this.targetProj, this.wgs84, {
+ x: extent.maxx,
+ y: extent.maxy
+ });
+
+ var box = {
+ minx: min.x,
+ miny: min.y,
+ maxx: max.x,
+ maxy: max.y
+ };
+
+ var matches = [];
+ var self = this;
+ for (var kmlId in this._kmls) {
+ if (this._kmls.hasOwnProperty(kmlId)) {
+ var kml = this._kmls[kmlId];
+ matches = kml.data.features.reduce(function (matches, feature, index) {
+ if (self.featureInBox(feature, box)) {
+ matches.push({
+ url: kml.url,
+ id: index
+ });
+ }
+ return matches;
+ }, matches);
}
- } else {
- var box = this.getBbox(feat);
- if (this.inBox(box[0], box[1], box[2], box[3], wgsbox.min.x, wgsbox.max.x, wgsbox.min.y, wgsbox.max.y) ) {
- matchedIds.push({
- url: itm.url,
- id: idx
- });
- return;
- }
- if ( this.inBox(box[0], box[1], box[2], box[3], wgsbox.min.x, wgsbox.max.x, wgsbox.min.x, wgsbox.max.x) ) {
- matchedIds.push({
- url: itm.url,
- id: idx
- });
- }
- // if (wgsbox.min.x < box[0] && wgsbox.max.x > box[2]) {
- // if (wgsbox.min.y > box[1] && wgsbox.min.y < box[3] || wgsbox.max.y > box[1] && wgsbox.max.y < box[3]) {
- // matchedIds.push({
- // url: itm.url,
- // id: idx
- // });
- // return;
- // }
- // }
- // if (wgsbox.min.y < box[1] && wgsbox.max.y > box[3]) {
- // if (wgsbox.min.x > box[0] && wgsbox.min.x < box[2] || wgsbox.max.x > box[0] && wgsbox.max.x < box[2]) {
- // matchedIds.push({
- // url: itm.url,
- // id: idx
- // });
- // return;
- // }
- // }
- // if (wgsbox.min.x < box[0] && wgsbox.max.x > box[2] && wgsbox.min.y > box[1] && wgsbox.max.y < box[3]) {
- // matchedIds.push({
- // url: itm.url,
- // id: idx
- // });
- // return;
- // }
}
+ return matches;
},
updateSelectedFeatures: function(ids, append) {
@@ -735,8 +832,6 @@
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
-
-
self.element.trigger('kml:error', "Problem talking to server: " + errorThrown);
}
});
@@ -841,7 +936,6 @@
getBbox: function(feature) {
switch (feature.geometry.type.toLowerCase()) {
case 'point':
- var map = $(this.element).mapbender();
var minx = feature.geometry.coordinates[0] - 0.001;
var miny = feature.geometry.coordinates[1] - 0.001;
return [minx, miny, minx + 0.002, miny + 0.002];
More information about the Mapbender_commits
mailing list