Skip to content

Commit

Permalink
Merge pull request #837 from theduckylittle/feature/keep-measure-tool…
Browse files Browse the repository at this point in the history
…-features

Measure Tool Enhancements
  • Loading branch information
klassenjs committed Jul 31, 2023
2 parents 74eb21f + 627e4bf commit 0ed1871
Show file tree
Hide file tree
Showing 25 changed files with 846 additions and 133 deletions.
2 changes: 1 addition & 1 deletion examples/desktop/mapbook.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
</map-source>

<map-source name="vector-parcels" type="mapserver-wfs">
<file>demo/parcels/parcels.map</file>
<file>./demo/parcels/parcels.map</file>
<param name="typename" value="ms:parcels"/>
<config name="pixel-tolerance" value="0"/>
<transform attribute="EMV_TOTAL" function="number"/>
Expand Down
4 changes: 2 additions & 2 deletions src/gm3/actions/mapSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ export function removeFeature(path, feature) {
if (mapSource) {
const idProp = mapSource.idProperty;
const id = feature.id || (feature.properties || {})[idProp];
if (mapSource.type === "vector") {
if (mapSource.type === "vector" || mapSource.type === "measure") {
// just remove the feature from an in memory layer.
dispatch(removeFeatureInternal({ mapSourceName, id }));
// return a resolved promise.
Expand Down Expand Up @@ -956,7 +956,7 @@ export function saveFeature(path, feature) {
if (mapSource) {
const idProp = mapSource.idProperty;
const id = feature.id || (feature.properties || {})[idProp];
if (mapSource.type === "vector") {
if (mapSource.type === "vector" || mapSource.type === "measure") {
// if this is a client side layer then just return
// the standard change events
if (!id) {
Expand Down
24 changes: 23 additions & 1 deletion src/gm3/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,28 @@ class Application {
})
);

this.store.dispatch(
mapSourceActions.add({
name: "measure",
type: "measure",
params: {},
config: {
"edit-attributes-on-add": false,
},
options: {
"always-on": true,
},
zIndex: 200001,
})
);
this.store.dispatch(
mapSourceActions.addLayer("measure", {
name: "measure",
on: true,
style: {},
})
);

// add a layer that listens for changes
// to the query results. This hs
this.store.dispatch(
Expand All @@ -224,7 +246,7 @@ class Application {
params: {},
// stupid high z-index to ensure results are
// on top of everything else.
zIndex: 200001,
zIndex: 200002,
})
);

Expand Down
97 changes: 59 additions & 38 deletions src/gm3/components/coordinate-display.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export default class CoordinateDisplay extends React.Component {
];
this.namedProjections = ["xy", "usng", "latlon"];
this.getProjectionCoords = this.getProjectionCoords.bind(this);
this.getCoordinateDisplay = this.getCoordinateDisplay.bind(this);

/**
* Validate specified projections
Expand Down Expand Up @@ -191,53 +190,75 @@ export default class CoordinateDisplay extends React.Component {
// TODO: The projection should be stored in the store,
// and defined by the user.
const mapProj = "EPSG:3857";
// transform the point
const coords = proj4(mapProj, projection.ref, this.props.coords);
// transform the point, slice is used to ensure only 2D coordinates.
const coords = proj4(
mapProj,
projection.ref,
this.props.coords.slice(0, 2)
);
return formatCoordinates(projection, coords);
}

getCoordinateDisplay(projection) {
let display = "";
getData(projection) {
switch (projection.ref) {
case "usng":
display = (
<span className="coordinates map-usng" key="usng">
<label>{projection.label}</label> {this.usng()}
</span>
);
break;
return {
label: projection.label,
point: this.usng(),
};
case "latlon":
display = (
<span className="coordinates map-latlon" key="latlon">
<label>{projection.label}</label> {this.latlon(projection)}
</span>
);
break;
return {
label: projection.label,
point: this.latlon(projection),
};
case "xy":
display = (
<span className="coordinates map-xy" key="xy">
<label>{projection.label}</label>{" "}
{formatCoordinates(projection, this.props.coords, 1)}
</span>
);
break;
default: {
const className =
"coordinates map-" + projection.ref.replace(/:/g, "-");
display = (
<span className={className} key={projection.ref}>
<label>{projection.label}</label>
{this.getProjectionCoords(projection)}
</span>
);
break;
}
return {
label: projection.label,
point: formatCoordinates(projection, this.props.coords, 1),
};
default:
return {
label: projection.label,
point: this.getProjectionCoords(projection),
};
}
return display;
}

render() {
const coordinateDisplays = this.projections.map(this.getCoordinateDisplay);
return <span className="coordinate-display">{coordinateDisplays}</span>;
if (this.props.asTable) {
return (
<div className="gm-grid">
<table>
{this.props.children}
<tbody>
{this.projections.map((projection) => {
const data = this.getData(projection);
return (
<tr key={projection.ref}>
<th>{data.label}</th>
<td>{data.point}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
return (
<span className="coordinate-display">
{this.projections.map((projection) => {
const className =
"coordinates map-" + projection.ref.replace(/:/g, "-");
const data = this.getData(projection);
return (
<span className={className} key={projection.ref}>
<label>{data.label}</label>
{data.point}
</span>
);
})}
</span>
);
}
}
2 changes: 1 addition & 1 deletion src/gm3/components/drawTool.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class DrawTool extends React.Component {
this.changeSelectLayer = this.changeSelectLayer.bind(this);

this.state = {
selectLayer: null,
selectLayer: props.layer || null,
};

if (this.props.geomType === "Select") {
Expand Down
65 changes: 65 additions & 0 deletions src/gm3/components/line-icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2023 Dan "Ducky" Little
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import React from "react";

export const LineIcon = ({ width, height, padding, outline, stroke }) => {
const points = [0, 0, width, height].join(" ");

return (
<svg
viewBox={`${-1 * padding} ${-1 * padding} ${width + padding * 2} ${
height + padding * 2
}`}
height={height}
width={width}
>
<polyline
points={points}
className="line-icon"
style={{
stroke: outline,
strokeWidth: 7,
strokeLineCap: "round",
}}
/>
<polyline
points={points}
className="line-icon"
style={{
stroke: stroke,
strokeWidth: 3,
}}
/>
</svg>
);
};

LineIcon.defaultProps = {
width: 32,
height: 32,
padding: 5,
outline: "#ffffff",
stroke: "#0099ff",
};
12 changes: 11 additions & 1 deletion src/gm3/components/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ import * as vectorLayer from "./layers/vector";
import * as bingLayer from "./layers/bing";
import * as usngLayer from "./layers/usng";
import { createLayer as createBlankLayer } from "./layers/blank";
import {
createLayer as createMeasureLayer,
updateLayer as updateMeasureLayer,
} from "./layers/measure";

import { wfsGetFeatures } from "./layers/wfs";
import { EDIT_LAYER_NAME } from "../../defaults";
Expand Down Expand Up @@ -171,6 +175,9 @@ class Map extends React.Component {
case "ags":
agsLayer.updateLayer(this.map, olLayer, mapSource);
break;
case "measure":
updateMeasureLayer(this.map, olLayer, mapSource);
break;
case "vector":
case "wfs":
case "ags-vector":
Expand Down Expand Up @@ -210,6 +217,8 @@ class Map extends React.Component {
return xyzLayer.createLayer(mapSource);
case "ags":
return agsLayer.createLayer(mapSource);
case "measure":
return createMeasureLayer(mapSource);
case "vector":
case "wfs":
case "ags-vector":
Expand Down Expand Up @@ -343,7 +352,6 @@ class Map extends React.Component {
this.removeRefreshInterval(mapSourceName);
}
}

this.renderQueryLayer();
}

Expand Down Expand Up @@ -734,6 +742,8 @@ class Map extends React.Component {
this.map.removeInteraction(this.drawTool);
// null out for logic.
this.drawTool = null;
// null out the sketch geometry
this.sketchFeature = null;

// and the current interaction
this.currentInteraction = null;
Expand Down
73 changes: 73 additions & 0 deletions src/gm3/components/map/layers/measure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2023 Dan "Ducky" Little
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import { Circle, Fill, Style, Stroke } from "ol/style";
import {
createLayer as createVectorLayer,
updateLayer as updateVectorLayer,
} from "./vector";

const applyMeasureStyle = (layer, mapSource, mapTool) => {
layer.setStyle((feature) => {
const { outlineColor, coreColor } = feature.getProperties();

if (feature.getGeometry().getType() === "Point") {
return new Style({
image: new Circle({
radius: 7,
fill: new Fill({
color: coreColor,
}),
stroke: new Stroke({
color: outlineColor,
width: 3,
}),
}),
});
}

return [
new Style({
stroke: new Stroke({
color: outlineColor,
width: 7,
}),
}),
new Style({
stroke: new Stroke({
color: coreColor,
width: 3,
}),
}),
];
});
};

export const createLayer = (mapSource) => {
return createVectorLayer(mapSource, applyMeasureStyle);
};

export const updateLayer = (map, layer, mapSource, mapTool) => {
return updateVectorLayer(map, layer, mapSource, mapTool, applyMeasureStyle);
};
Loading

0 comments on commit 0ed1871

Please sign in to comment.