UNPKG

react-planner-electron

Version:

react-planner-electron is a React Component for plans design. Draw a 2D floorplan and navigate it in 3D mode.

221 lines (173 loc) 7.91 kB
import { Map, List } from 'immutable'; import { Vertex as VertexModel } from '../models'; import { IDBroker, GeometryUtils, SnapSceneUtils, SnapUtils } from '../utils/export'; import { MODE_DRAGGING_VERTEX, MODE_IDLE } from '../constants'; import { Layer, Line, Group } from '../class/export'; class Vertex{ static add( state, layerID, x, y, relatedPrototype, relatedID ) { let vertex = state.getIn(['scene', 'layers', layerID, 'vertices']).find(vertex => GeometryUtils.samePoints(vertex, {x, y})); if (vertex) { vertex = vertex.update(relatedPrototype, related => related.push(relatedID)); } else { vertex = new VertexModel({ id: IDBroker.acquireID(), name: 'Vertex', x, y, [relatedPrototype]: new List([relatedID]) }); } state = state.setIn(['scene', 'layers', layerID, 'vertices', vertex.id], vertex); return { updatedState: state, vertex }; } static setAttributes(state, layerID, vertexID, vertexAttributes) { state = state.mergeIn(['scene', 'layers', layerID, 'vertices', vertexID ], vertexAttributes) return { updatedState: state }; } static addElement( state, layerID, vertexID, elementPrototype, elementID ) { state = state.updateIn(['scene', 'layers', layerID, 'vertices', vertexID, elementPrototype], list => list.push( elementID ) ); return { updatedState: state }; } static removeElement( state, layerID, vertexID, elementPrototype, elementID ) { let elementIndex = state.getIn(['scene', 'layers', layerID, 'vertices', vertexID, elementPrototype]).findIndex( el => el === elementID ); if( elementIndex !== -1 ) { state = state.updateIn(['scene', 'layers', layerID, 'vertices', vertexID, elementPrototype], list => list.remove( elementIndex ) ); } return { updatedState: state }; } static select( state, layerID, vertexID ){ state = state.setIn(['scene', 'layers', layerID, 'vertices', vertexID, 'selected'], true); state = state.updateIn(['scene', 'layers', layerID, 'selected', 'vertices'], elems => elems.push(vertexID)); return { updatedState: state }; } static unselect( state, layerID, vertexID ){ state = state.setIn(['scene', 'layers', layerID, 'vertices', vertexID, 'selected'], false); state = state.updateIn(['scene', 'layers', layerID, 'selected', 'vertices'], elems => elems.filter( el => el.id !== vertexID )); return { updatedState: state }; } static remove( state, layerID, vertexID, relatedPrototype, relatedID, forceRemove ) { let vertex = state.getIn(['scene', 'layers', layerID, 'vertices', vertexID]); if( vertex ) { if( relatedPrototype && relatedID ) vertex = vertex.update(relatedPrototype, related => { let index = related.findIndex(ID => relatedID === ID); return related.delete(index); }); let inUse = vertex.areas.size || vertex.lines.size; if( inUse && !forceRemove ) { state = state.setIn(['scene', 'layers', layerID, 'vertices', vertexID], vertex); } else { state = state.deleteIn(['scene', 'layers', layerID, 'vertices', vertexID]); } } return { updatedState: state }; } static beginDraggingVertex(state, layerID, vertexID, x, y) { let snapElements = SnapSceneUtils.sceneSnapElements(state.scene, new List(), state.snapMask); state = state.merge({ mode: MODE_DRAGGING_VERTEX, snapElements, draggingSupport: Map({ layerID, vertexID, previousMode: state.get('mode') }) }); return { updatedState: state }; } static updateDraggingVertex(state, x, y) { let { draggingSupport, snapElements, scene } = state; let snap = null; if (state.snapMask && !state.snapMask.isEmpty()) { snap = SnapUtils.nearestSnap(snapElements, x, y, state.snapMask); if (snap) ({ x, y } = snap.point); } let layerID = draggingSupport.get('layerID'); let vertexID = draggingSupport.get('vertexID'); state = state.merge({ activeSnapElement: snap ? snap.snap : null, scene: scene.mergeIn(['layers', layerID, 'vertices', vertexID], { x, y }) }); return { updatedState: state }; } static endDraggingVertex(state, x, y) { let { draggingSupport } = state; let layerID = draggingSupport.get('layerID'); let vertexID = draggingSupport.get('vertexID'); let lines = state.getIn(['scene', 'layers', layerID, 'vertices', vertexID, 'lines']); if( lines ) { state = lines.reduce( ( reducedState, lineID ) => { if( !reducedState.getIn(['scene', 'layers', layerID, 'lines', lineID])) return reducedState; let v_id0 = reducedState.getIn(['scene', 'layers', layerID, 'lines', lineID, 'vertices', 0]); let v_id1 = reducedState.getIn(['scene', 'layers', layerID, 'lines', lineID, 'vertices', 1]); let oldVertexID = v_id0 === vertexID ? v_id1 : v_id0; let oldVertex = reducedState.getIn(['scene', 'layers', layerID, 'vertices', oldVertexID]); let vertex = reducedState.getIn(['scene', 'layers', layerID, 'vertices', vertexID]); let oldHoles = []; let orderedVertices = GeometryUtils.orderVertices([oldVertex, vertex]); let holes = reducedState .getIn(['scene', 'layers', layerID, 'lines', lineID, 'holes']) .forEach(holeID => { let hole = reducedState.getIn(['scene', 'layers', layerID, 'holes', holeID]); let oldLineLength = GeometryUtils.pointsDistance(oldVertex.x, oldVertex.y, vertex.x, vertex.y); let offset = GeometryUtils.samePoints( orderedVertices[1], reducedState.getIn(['scene', 'layers', layerID, 'lines', lineID, 'vertices', 1]) ) ? ( 1 - hole.offset ) : hole.offset; let offsetPosition = GeometryUtils.extendLine( oldVertex.x, oldVertex.y, vertex.x, vertex.y, oldLineLength * offset ); oldHoles.push({hole, offsetPosition}); }); let lineType = reducedState.getIn(['scene', 'layers', layerID, 'lines', lineID, 'type']); let lineProps = reducedState.getIn(['scene', 'layers', layerID, 'lines', lineID, 'properties']); let lineGroups = reducedState //get groups membership if present .getIn(['scene', 'groups']) .filter( group => { const lines = group.getIn(['elements', layerID, 'lines']); return lines && lines.contains(lineID); }); reducedState = Layer.removeZeroLengthLines( reducedState, layerID ).updatedState; reducedState = Layer.mergeEqualsVertices( reducedState, layerID, vertexID ).updatedState; reducedState = Line.remove( reducedState, layerID, lineID ).updatedState; if (!GeometryUtils.samePoints(oldVertex, vertex)) { let ret = Line.createAvoidingIntersections( reducedState, layerID, lineType, oldVertex.x, oldVertex.y, vertex.x, vertex.y, lineProps, oldHoles ); reducedState = ret.updatedState; //re-add to old line's groups if present ret.lines.forEach( addedLine => { lineGroups.forEach( oldLineGroup => { reducedState = Group.addElement( reducedState, oldLineGroup.id, layerID, 'lines', addedLine.id ).updatedState; }); }); } return reducedState; }, state ); } state = Layer.detectAndUpdateAreas( state, layerID ).updatedState; state = state.merge({ mode: draggingSupport.get('previousMode'), draggingSupport: null, activeSnapElement: null, snapElements: new List() }); return { updatedState: state }; } } export { Vertex as default };