UNPKG

leaflet-craft

Version:

Zoopla inspired freehand polygon creation using Leaflet.js.

142 lines (114 loc) 5.9 kB
import { rawLatLngKey, polygonID, polygons } from '../FreeDraw'; import { removeFor, createFor } from './Polygon'; import Stack from './Stack'; import { undoMainStack, undoStackObject, redoMainStack, redoStackObject, mergedPolygonsMap } from './UndoRedo'; import { pubSub } from '../FreeDraw'; // The current Polygon is merged Polygon . // Add the merged polygon in Undo Stack which is mapped to [intersectingPolygons - current Polygon] export const mergedPolygonCreatedHandler = data => { undoMainStack.push(data.count); undoStackObject[data.count] = Stack(); undoStackObject[data.count].push(data.addedPolygons[0]); data.options.mergedFromPolygons && (mergedPolygonsMap[data.count] = data.options.mergedFromPolygons); return; }; // the current polygon came from Undo . (special Case) export const mergePolygonUndoHandler = data => { if (!undoStackObject[data.pid]) { undoStackObject[data.pid] = new Stack(); } // Remove from undoStackObject the latest state of pid . undoStackObject[data.pid].pop(); // Add the new Polygon which has now listeners attached to undoMainStack . undoStackObject[data.pid].push(data.addedPolygons[0]); return; }; // Redo operation performed on a merged Polygon. // Add the merged polygon in Undo Stack which is mapped to [intersectingPolygons - current Polygon] export const mergePolygonRedoHandler = data => { undoMainStack.push(data.pid); undoStackObject[data.pid] = Stack(); undoStackObject[data.pid].push(data.addedPolygons[0]); data.options.mergedFromPolygons && (mergedPolygonsMap[data.pid] = data.options.mergedFromPolygons); return; }; // Polygon is not overlapping! export const newPolygonCreatedHandler = data => { // new Polygon is created -> Clear REDO Stack . redoMainStack.clear(); redoStackObject.clear(); const limitReached = polygons.get(data.map).size === data.options.maximumPolygons; // if new Polygon is created and it is intersecting -> do not add to Undo Stack . ; if (data.isIntersecting && !limitReached && !data.preventMutations && polygons.get(data.map).size > 1 && data.options.mergePolygons) { return; } undoStackObject[data.count] = Stack(); undoStackObject[data.count].push(data.addedPolygons[0]); undoMainStack.push(data.count); return; }; // Polygon is not overlapping! export const existingPolygonEditedHandler = data => { if (!undoStackObject[data.pid]) { undoStackObject[data.pid] = new Stack(); } // comes in edit mode and does not merges/ self-intersects AND add to main Stack . if (!data.from) { undoMainStack.push(data.pid); } // comes in Undo Listener and does not merges/ self-intersects . undoStackObject[data.pid].push(data.addedPolygons[0]); return; }; export const undoHandler = map => { // DELETE POLYGON AND HANDLING STATES LOGIC : // Pop from Undo_Main_Stack and push to Redo_Main_Stack . const id = undoMainStack.length ? undoMainStack.pop() : 0; id && redoMainStack.push(id); // Pop the polygon currently visible on Screen via the "id" from the undo_stack_Object. const undoPoppedEl = id && undoStackObject[id] ? undoStackObject[id].pop() : 0; if (!redoStackObject[id]) { redoStackObject[id] = new Stack(); } // Add the polygon to redo_stack_Object and remove the popped polygon from the screen. undoPoppedEl && redoStackObject[id].push(undoPoppedEl); undoPoppedEl && removeFor(map, undoPoppedEl); // CREATE POLYGON LOGIC : // check if Undo_Main_Stack is not empty and corresponding undo_stack_Object is also not empty. if (id && !undoStackObject[id].empty()) { // The new Polygon to be created is now at the top of undo_stack_Object. const revertedToPoly = undoStackObject[id].pop(); createFor(map, revertedToPoly[rawLatLngKey], revertedToPoly._options, true, id, 1); } else if (mergedPolygonsMap[id] && mergedPolygonsMap[id].length !== 0) { // Current Polygon is a merged polygon, so create polygons from which it is made. mergedPolygonsMap[id].forEach(element => { createFor(map, element[rawLatLngKey], element._options, true, element[polygonID], 3); // Should not Update undoStack State . }); } pubSub.publish('STACK_STATE_UPDATED', { map, undoMainStack, redoMainStack }); pubSub.publish('edit-end'); }; export const redoHandler = map => { // Pop the id of polygon and the polygon itself from Redo_Main_Stack and redo_stack_Object respectively. const id = redoMainStack.pop(); const redoPoppedEl = id ? redoStackObject[id].pop() : 0; // Get the element that we have to remove which is currently on the Screen. const currentEl = id && undoStackObject[id].length() ? undoStackObject[id].top() : 0; if (currentEl) { // remove the polygon currently on Screen. removeFor(map, currentEl); // Create the polygon which we had popped from redo_stack_Object. redoPoppedEl && createFor(map, redoPoppedEl[rawLatLngKey], redoPoppedEl._options, true, id, 0); } else if (mergedPolygonsMap[id] && mergedPolygonsMap[id].length !== 0) { // The polygon to be made is a merged Polygon, hence removing all the polygons which are overlapping (merged) and then creating the merged polygon. mergedPolygonsMap[id].forEach(element => { removeFor(map, undoStackObject[element[polygonID]].top()); }); createFor(map, redoPoppedEl[rawLatLngKey], redoPoppedEl._options, true, id, 4); } else { // If Polygon has no State in UNDO STACK -> Simply draw REDO polygon redoPoppedEl && createFor(map, redoPoppedEl[rawLatLngKey], redoPoppedEl._options, true, id, 0); } pubSub.publish('STACK_STATE_UPDATED', { map, undoMainStack, redoMainStack }); pubSub.publish('edit-end'); };