Skip to content

Commit

Permalink
Additional improvements to the measure tool
Browse files Browse the repository at this point in the history
- Table view for points
- Ensure features are not cleared when changing tools
- Unique colors for each feature
  • Loading branch information
theduckylittle committed Jun 2, 2023
1 parent 69da05b commit a4df02a
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 82 deletions.
88 changes: 52 additions & 36 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 @@ -196,48 +195,65 @@ export default class CoordinateDisplay extends React.Component {
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>
<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>
);
}
}
58 changes: 49 additions & 9 deletions src/gm3/components/map/layers/measure.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,62 @@
* SOFTWARE.
*/

import { Style, Stroke } from "ol/style";

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

const CORE_COLORS = [
"#1b9e77",
"#d95f02",
"#7570b3",
"#e7298a",
"#66a61e",
"#e6ab02",
"#a6761d",
];
const OUTLINE_COLORS = ["#f0f0f0", "#ffffb3", "#e41a1c"];

const applyMeasureStyle = (layer, mapSource, mapTool) => {
layer.setStyle(
new Style({
stroke: new Stroke({
color: "blue",
width: 5,
layer.setStyle((feature) => {
const idx =
feature.getProperties().index %
(CORE_COLORS.length * OUTLINE_COLORS.length);

const coreColor = CORE_COLORS[idx % CORE_COLORS.length];
const outlineColor = OUTLINE_COLORS[Math.floor(idx / CORE_COLORS.length)];

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) => {
Expand Down
100 changes: 63 additions & 37 deletions src/gm3/components/measure/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2017 Dan "Ducky" Little
* Copyright (c) 2017, 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
Expand Down Expand Up @@ -29,13 +29,14 @@ import { getArea } from "ol/sphere";

import DrawTool from "../drawTool";
import { changeTool } from "../../actions/map";
import { clearFeatures } from "../../actions/mapSource";
import { clearFeatures, saveFeature } from "../../actions/mapSource";
import { PolygonIcon } from "../polygon-icon";

import * as util from "../../util";
import { projectFeatures } from "../../util";

import { toLonLat } from "ol/proj";
import { UnitOption } from "./unit";

import CoordinateDisplay from "../coordinate-display";

Expand All @@ -46,11 +47,24 @@ import {
deconstructPolygon,
} from "./calc";

const LENGTH_KEY = "gm3:length-units";
const AREA_KEY = "gm3:area-units";

export class MeasureTool extends Component {
constructor(props) {
super(props);

// look for unit measurements from local storage.
const savedLengthUnits = localStorage.getItem(LENGTH_KEY) || "ft";
const savedAreaUnits = localStorage.getItem(AREA_KEY) || "ft";

this.state = {
units: this.props.initialUnits ? this.props.initialUnits : "ft",
lengthUnits: this.props.initialUnits
? this.props.initialUnits
: savedLengthUnits,
areaUnits: this.props.initialUnits
? this.props.initialUnits
: savedAreaUnits,
};

// localize all of the ordinals
Expand All @@ -68,8 +82,21 @@ export class MeasureTool extends Component {
}

componentDidUpdate(prevProps) {
if (prevProps.interactionType !== this.props.interactionType) {
this.props.clearFeatures(util.getMapSourceName(this.props.targetLayer));
// check to see if a feature was added to the mapSource
if (
prevProps.measureSource.features.length !==
this.props.measureSource.features.length
) {
const features = this.props.measureSource.features;
const feature = features[features.length - 1];
const nextFeature = {
...feature,
properties: {
...feature.properties,
index: features.length - 1,
},
};
this.props.saveFeature(this.props.targetLayer, nextFeature);
}
}

Expand All @@ -95,7 +122,7 @@ export class MeasureTool extends Component {
for (let i = 0, ii = segments.length; i < ii; i++) {
const seg = segments[i];
const lineLength = chompFloat(
util.metersLengthToUnits(seg.len, this.state.units),
util.metersLengthToUnits(seg.len, this.state.lengthUnits),
2
);
totalLength += lineLength;
Expand Down Expand Up @@ -130,7 +157,7 @@ export class MeasureTool extends Component {
<th></th>
<th>
{this.props.t("measure-segment-length")} (
{this.props.t(`units-${this.state.units}`)})
{this.props.t(`units-${this.state.lengthUnits}`)})
</th>
<th>{this.props.t("measure-bearing", "Bearing")}</th>
</tr>
Expand All @@ -153,7 +180,9 @@ export class MeasureTool extends Component {

const formatArea = (polygon) => {
const areaMeters = getArea(util.jsonToGeom(polygon));
return util.metersAreaToUnits(areaMeters, this.state.units).toFixed(2);
return util
.metersAreaToUnits(areaMeters, this.state.areaUnits)
.toFixed(2);
};

return (
Expand All @@ -164,7 +193,7 @@ export class MeasureTool extends Component {
<th></th>
<th>
{this.props.t("measure-area")} ({this.props.t("measure-sq")}{" "}
{this.props.t(`units-${this.state.units}`)})
{this.props.t(`units-${this.state.areaUnits}`)})
</th>
</tr>
</thead>
Expand Down Expand Up @@ -203,6 +232,7 @@ export class MeasureTool extends Component {
} else if (g.type === "Point") {
return (
<CoordinateDisplay
asTable
coords={g.coordinates}
projections={this.props.pointProjections}
resolution={this.props.map.resolution}
Expand Down Expand Up @@ -248,23 +278,6 @@ export class MeasureTool extends Component {
this.setState({ units: value });
}

renderUnitOption(value, isSq) {
const selected = this.state.units === value ? "selected" : "";
return (
<div
key={"units-" + value}
className={"radio-option " + selected}
onClick={() => {
this.changeUnits(value);
}}
>
<i className="radio-icon"></i>{" "}
{isSq ? `${this.props.t("measure-sq")} ` : ""}
{this.props.t(`units-${value}`)}
</div>
);
}

renderUnitOptions() {
const units = this.props.t("units");
let measurementType = this.props.map.interactionType;
Expand All @@ -278,23 +291,35 @@ export class MeasureTool extends Component {
return (
<div className="measure-units">
<b>{units}:</b>
{this.renderUnitOption("m")}
{this.renderUnitOption("km")}
{this.renderUnitOption("ft")}
{this.renderUnitOption("mi")}
{this.renderUnitOption("ch")}
{["m", "km", "ft", "mi", "ch"].map((unit) => (
<UnitOption
key={unit}
unit={unit}
selected={unit === this.state.lengthUnits}
onClick={() => {
localStorage.setItem(LENGTH_KEY, unit);
this.setState({ lengthUnits: unit });
}}
/>
))}
</div>
);
} else if (measurementType && measurementType.indexOf("Polygon") >= 0) {
return (
<div className="measure-units">
<b>{units}:</b>
{this.renderUnitOption("m", true)}
{this.renderUnitOption("km", true)}
{this.renderUnitOption("ft", true)}
{this.renderUnitOption("mi", true)}
{this.renderUnitOption("a")}
{this.renderUnitOption("h")}
{["m", "km", "ft", "mi", "a", "h"].map((unit) => (
<UnitOption
key={unit}
unit={unit}
isSq={unit !== "a" && unit !== "h"}
selected={unit === this.state.areaUnits}
onClick={() => {
localStorage.setItem(AREA_KEY, unit);
this.setState({ areaUnits: unit });
}}
/>
))}
</div>
);
} else {
Expand Down Expand Up @@ -365,6 +390,7 @@ const mapToProps = (state) => ({
const mapDispatchToProps = {
changeTool,
clearFeatures,
saveFeature,
};

export default connect(
Expand Down
Loading

0 comments on commit a4df02a

Please sign in to comment.