Skip to content

Commit

Permalink
add undo for field editor
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhughes27 committed Aug 23, 2018
1 parent 964552d commit 4f063f2
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 36 deletions.
85 changes: 57 additions & 28 deletions clients/admin_next/src/views/Fields/FieldsEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import UpdateFieldMutation from "../../mutations/UpdateField";
import CreateFieldMutation from "../../mutations/CreateField";
import { showNotice } from "../../components/Notice";
import quadrilateralise from "./quadrilateralise";
import { merge } from "lodash";
import { merge, last } from "lodash";

interface Props {
map: FieldsEditor_map;
Expand Down Expand Up @@ -47,6 +47,7 @@ const newField = {
class FieldsEditor extends React.Component<Props, State> {
mapRef = React.createRef<Map>();
map?: Leaflet.Map;
historyBuffer: any[] = [];

constructor(props: Props) {
super(props);
Expand Down Expand Up @@ -77,6 +78,7 @@ class FieldsEditor extends React.Component<Props, State> {
}

addField = () => {
this.resetEditing();
this.map!.editTools.startPolygon();
this.map!.on("contextmenu", this.startDrawingMobile);
this.map!.on("editable:drawing:clicked", this.autoComplete);
Expand All @@ -86,10 +88,16 @@ class FieldsEditor extends React.Component<Props, State> {
editField = (field: FieldsEditor_fields[0], polygon: Leaflet.Polygon) => {
this.resetEditing();
polygon.enableEdit();

const geoJson = JSON.parse(field.geoJson);
this.historyBuffer.push(geoJson);

this.setState({mode: "editField", editing: field});
}

resetEditing = () => {
this.historyBuffer = [];

this.map!.eachLayer((layer: Leaflet.ILayer) => {
const polygon = layer as Leaflet.Polygon;
if (polygon.disableEdit) { polygon.disableEdit(); }
Expand All @@ -110,46 +118,37 @@ class FieldsEditor extends React.Component<Props, State> {

updateField = (event: Leaflet.LeafletGeoJSONEvent) => {
const polygon = event.layer as Leaflet.Polygon;

const {lat, lng: long} = polygon.getBounds().getCenter();
const geoJson = polygon.toGeoJSON();

const editing = {...this.state.editing};
merge(editing, {lat, long, geoJson: JSON.stringify(geoJson)});
this.setEditingState(geoJson);
}

this.setState({editing});
undoEdit = () => {
if (this.historyBuffer.length > 1) {
this.historyBuffer.pop();
const geoJson = last(this.historyBuffer);

this.historyBuffer.pop();
this.setEditingState(geoJson);
}
}

squareFieldCorners = () => {
const geoJson = JSON.parse(this.state.editing.geoJson);
const orthGeoJson = quadrilateralise(geoJson, this.map!);
const layer = this.editingLayer();

this.replaceLayer(layer, orthGeoJson);
}

editingLayer = () => {
const layers = new Leaflet.LayerGroup();

this.map!.eachLayer((l) => {
const p = l as Leaflet.Polygon;
if (p.editEnabled && p.editEnabled()) {
layers.addLayer(p);
}
});

return layers;
this.setEditingState(orthGeoJson);
}

replaceLayer = (layers: Leaflet.LayerGroup<Leaflet.ILayer>, geoJson: any) => {
layers.eachLayer((l) => this.map!.removeLayer(l));
setEditingState = (geojson: any) => {
const newLayer = this.replaceLayer(geojson);
const {lat, lng: long} = newLayer.getBounds().getCenter();

const newLayers = Leaflet.geoJson(geoJson, {style: () => FieldStyle}).addTo(this.map!);
const editing = {...this.state.editing};
merge(editing, {lat, long, geoJson: JSON.stringify(geojson)});

newLayers.eachLayer((l) => {
const p = l as Leaflet.Polygon;
p.enableEdit();
});
this.historyBuffer.push(geojson);
this.setState({editing});
}

// https://github.com/Leaflet/Leaflet.Editable/blob/master/src/Leaflet.Editable.js#L389
Expand All @@ -168,6 +167,35 @@ class FieldsEditor extends React.Component<Props, State> {
}
}

/* Manage Leaflet state */
replaceLayer = (geoJson: any) => {
const layers = this.editingLayer();

layers.eachLayer((l) => this.map!.removeLayer(l));

const newLayers = Leaflet.geoJson(geoJson, {style: () => FieldStyle}).addTo(this.map!);

newLayers.eachLayer((l) => {
const p = l as Leaflet.Polygon;
p.enableEdit();
});

return newLayers.getLayers()[0] as Leaflet.Polygon;
}

editingLayer = () => {
const layers = new Leaflet.LayerGroup();

this.map!.eachLayer((l) => {
const p = l as Leaflet.Polygon;
if (p.editEnabled && p.editEnabled()) {
layers.addLayer(p);
}
});

return layers;
}

/* Input event handlers */
placeSelected = (lat: number, long: number) => {
const defaultZoom = 15;
Expand Down Expand Up @@ -263,6 +291,7 @@ class FieldsEditor extends React.Component<Props, State> {
mode={this.state.mode}
geojson={this.state.editing.geoJson}
squareFieldCorners={this.squareFieldCorners}
undoEdit={this.undoEdit}
/>
<FieldsEditorActions
mode={this.state.mode}
Expand Down
26 changes: 18 additions & 8 deletions clients/admin_next/src/views/Fields/FieldsEditorControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import * as React from "react";
import Control from "react-leaflet-control";
import MapTooltip from "./MapTooltip";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faVectorSquare } from "@fortawesome/free-solid-svg-icons";
import { faVectorSquare, faUndo } from "@fortawesome/free-solid-svg-icons";

interface Props {
mode: "none" | "view" | "editMap" | "addField" | "editField";
geojson: string;
squareFieldCorners: () => void;
undoEdit: () => void;
}

class FieldsEditorControls extends React.Component<Props> {
Expand All @@ -16,13 +17,22 @@ class FieldsEditorControls extends React.Component<Props> {

if ((mode === "addField" || mode === "editField") && geojson !== "") {
return (
<Control position="topleft">
<MapTooltip text={"Square Corners"}>
<button className="fields-editor-control" onClick={this.props.squareFieldCorners}>
<FontAwesomeIcon icon={faVectorSquare} />
</button>
</MapTooltip>
</Control>
<div>
<Control position="topleft">
<MapTooltip text={"Square Corners"}>
<button className="fields-editor-control" onClick={this.props.squareFieldCorners}>
<FontAwesomeIcon icon={faVectorSquare} />
</button>
</MapTooltip>
</Control>
<Control position="topleft">
<MapTooltip text={"Undo"}>
<button className="fields-editor-control" onClick={this.props.undoEdit}>
<FontAwesomeIcon icon={faUndo} />
</button>
</MapTooltip>
</Control>
</div>
);
} else {
return null;
Expand Down

0 comments on commit 4f063f2

Please sign in to comment.