Skip to content

Commit

Permalink
Merge pull request #834 from kevinhughes27/field-editor-undo
Browse files Browse the repository at this point in the history
add undo for field editor
  • Loading branch information
kevinhughes27 authored Aug 23, 2018
2 parents 964552d + 3558fd7 commit 7774417
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 36 deletions.
1 change: 1 addition & 0 deletions clients/admin_next/src/assets/jss/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const SubmitButton = (theme: Theme) => createStyles({
position: "fixed",
bottom: theme.spacing.unit * 2,
right: theme.spacing.unit * 2,
zIndex: 1000,
},
inline: {
marginTop: 20,
Expand Down
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 7774417

Please sign in to comment.