comparison client/src/map/Maplayer.vue @ 1063:7ec2133c6404

client: add area measurement. simpify code * Add a third draw mode which can only be activated when no morphology is selected and we are already in LineString mode. It adds an area calculation. Because the Polygon drawMode ends on a double click, there needs to be an extra callback for this to run identify so that the area calculation is shown all times. * Add Bernhard as author to some files and also simplify copyright note. * Remove DRAWMODES in the code to simplify as this is just one indirection used once in stores/application.js. * Use mapState instead mapGetters to get the drawMode at all places to save some code lines.
author Bernhard Reiter <bernhard@intevation.de>
date Thu, 25 Oct 2018 23:16:53 +0200
parents d3bdad8ed8d3
children 907321455f39 3f14b73414e2
comparison
equal deleted inserted replaced
1062:d3bdad8ed8d3 1063:7ec2133c6404
47 import LineString from "ol/geom/LineString.js"; 47 import LineString from "ol/geom/LineString.js";
48 import Point from "ol/geom/Point.js"; 48 import Point from "ol/geom/Point.js";
49 import Draw from "ol/interaction/Draw.js"; 49 import Draw from "ol/interaction/Draw.js";
50 import { Vector as VectorLayer } from "ol/layer.js"; 50 import { Vector as VectorLayer } from "ol/layer.js";
51 import { Vector as VectorSource } from "ol/source.js"; 51 import { Vector as VectorSource } from "ol/source.js";
52 import { getLength } from "ol/sphere.js"; 52 import { getLength, getArea } from "ol/sphere.js";
53 import { Icon, Stroke, Style, Fill } from "ol/style.js"; 53 import { Icon, Stroke, Style, Fill } from "ol/style.js";
54 54
55 import { displayError } from "../application/lib/errors.js"; 55 import { displayError } from "../application/lib/errors.js";
56 import { calculateFairwayCoordinates } from "../application/lib/geo.js"; 56 import { calculateFairwayCoordinates } from "../application/lib/geo.js";
57 57
103 width: 2 103 width: 2
104 }) 104 })
105 }) 105 })
106 ]; 106 ];
107 107
108 geometry.forEachSegment(function(start, end) { 108 if (geometry.getType() === "LineString") {
109 var dx = end[0] - start[0]; 109 geometry.forEachSegment(function(start, end) {
110 var dy = end[1] - start[1]; 110 var dx = end[0] - start[0];
111 var rotation = Math.atan2(dy, dx); 111 var dy = end[1] - start[1];
112 // arrows 112 var rotation = Math.atan2(dy, dx);
113 styles.push( 113 // arrows
114 new Style({ 114 styles.push(
115 geometry: new Point(end), 115 new Style({
116 image: new Icon({ 116 geometry: new Point(end),
117 // we need to make sure the image is loaded by Vue Loader 117 image: new Icon({
118 src: require("../application/assets/linestring_arrow.png"), 118 // we need to make sure the image is loaded by Vue Loader
119 // fiddling with the anchor's y value does not help to 119 src: require("../application/assets/linestring_arrow.png"),
120 // position the image more centered on the line ending, as the 120 // fiddling with the anchor's y value does not help to
121 // default line style seems to be slightly uncentered in the 121 // position the image more centered on the line ending, as the
122 // anti-aliasing, but the image is not placed with subpixel 122 // default line style seems to be slightly uncentered in the
123 // precision 123 // anti-aliasing, but the image is not placed with subpixel
124 anchor: [0.75, 0.5], 124 // precision
125 rotateWithView: true, 125 anchor: [0.75, 0.5],
126 rotation: -rotation 126 rotateWithView: true,
127 rotation: -rotation
128 })
127 }) 129 })
128 }) 130 );
129 ); 131 });
130 }); 132 }
131
132 return styles; 133 return styles;
133 }, 134 },
134 createVectorLayer() { 135 createVectorLayer() {
135 this.vectorLayer = new VectorLayer({ 136 this.vectorLayer = new VectorLayer({
136 source: this.vectorSource, 137 source: this.vectorSource,
139 }, 140 },
140 removeCurrentInteraction() { 141 removeCurrentInteraction() {
141 this.openLayersMap.removeInteraction(this.interaction); 142 this.openLayersMap.removeInteraction(this.interaction);
142 this.interaction = null; 143 this.interaction = null;
143 }, 144 },
144 createInteraction() { 145 createInteraction(drawMode) {
145 this.vectorSource.clear(); 146 this.vectorSource.clear();
146 var draw = new Draw({ 147 var draw = new Draw({
147 source: this.vectorSource, 148 source: this.vectorSource,
148 type: this.drawMode, 149 type: drawMode,
149 maxPoints: 2 150 maxPoints: drawMode === "LineString" ? 2 : 50
150 }); 151 });
151 draw.on("drawstart", event => { 152 draw.on("drawstart", event => {
152 this.vectorSource.clear(); 153 this.vectorSource.clear();
153 this.$store.commit("identifystore/setCurrentMeasurement", null); 154 this.$store.commit("identifystore/setCurrentMeasurement", null);
154 event.feature.setId("drawn.1"); // unique id for new feature 155 event.feature.setId("drawn.1"); // unique id for new feature
155 }); 156 });
156 draw.on("drawend", this.drawEnd); 157 draw.on("drawend", this.drawEnd);
157 return draw; 158 return draw;
158 }, 159 },
159 drawEnd(event) { 160 drawEnd(event) {
160 const length = getLength(event.feature.getGeometry()); 161 if (this.drawMode === "Polygon") {
161 this.$store.commit("identifystore/setCurrentMeasurement", length); 162 const areaSize = getArea(event.feature.getGeometry());
162 // also place the a rounded length in a property, so identify can show it 163 // also place the a rounded areaSize in a property,
163 event.feature.set("length (m)", Math.round(length * 10) / 10); 164 // so identify will show it
165 event.feature.set("area (kmĀ²)", Math.round(areaSize) / 1000);
166 }
167 if (this.drawMode === "LineString") {
168 const length = getLength(event.feature.getGeometry());
169 this.$store.commit("identifystore/setCurrentMeasurement", length);
170 // also place the a rounded length in a property,
171 // so identify will show it
172 event.feature.set("length (m)", Math.round(length * 10) / 10);
173 }
164 174
165 // if a survey has been selected, request a profile 175 // if a survey has been selected, request a profile
166 // TODO an improvement could be to check if the line intersects 176 // TODO an improvement could be to check if the line intersects
167 // with the bottleneck area's polygon before trying the server request 177 // with the bottleneck area's polygon before trying the server request
168 if (this.selectedMorph) { 178 if (this.selectedMorph) {
227 this.interaction = interaction; 237 this.interaction = interaction;
228 this.openLayersMap.addInteraction(interaction); 238 this.openLayersMap.addInteraction(interaction);
229 }, 239 },
230 activateIdentifyMode() { 240 activateIdentifyMode() {
231 this.openLayersMap.on("singleclick", event => { 241 this.openLayersMap.on("singleclick", event => {
232 // console.log("single click on map:", event); 242 this.identify(event.coordinate, event.pixel);
243 });
244 this.openLayersMap.on("dblclick", event => {
233 this.identify(event.coordinate, event.pixel); 245 this.identify(event.coordinate, event.pixel);
234 }); 246 });
235 }, 247 },
236 identify(coordinate, pixel) { 248 identify(coordinate, pixel) {
237 this.$store.commit("identifystore/setIdentifiedFeatures", []); 249 this.$store.commit("identifystore/setIdentifiedFeatures", []);
360 // reported that this was not feasable (back then). 372 // reported that this was not feasable (back then).
361 // console.log("onAfterPrint(", evt, ")"); 373 // console.log("onAfterPrint(", evt, ")");
362 } 374 }
363 }, 375 },
364 watch: { 376 watch: {
365 drawMode() { 377 drawMode(newValue) {
366 if (this.interaction) { 378 if (this.interaction) {
367 this.removeCurrentInteraction(); 379 this.removeCurrentInteraction();
368 } else { 380 }
381 if (newValue) {
369 this.activateInteraction(); 382 this.activateInteraction();
370 } 383 }
371 }, 384 },
372 split() { 385 split() {
373 const map = this.openLayersMap; 386 const map = this.openLayersMap;