UNPKG

react-planner

Version:

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

413 lines (332 loc) 16.5 kB
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } import { Map, List, fromJS } from 'immutable'; import { Layer, Group } from './export'; import { IDBroker, NameGenerator } from '../utils/export'; import { nearestSnap, addLineSegmentSnap } from '../utils/snap'; import { MODE_IDLE, MODE_DRAWING_HOLE, MODE_DRAGGING_HOLE } from '../constants'; import { GeometryUtils } from '../utils/export'; var Hole = function () { function Hole() { _classCallCheck(this, Hole); } _createClass(Hole, null, [{ key: 'create', value: function create(state, layerID, type, lineID, offset, properties) { var holeID = IDBroker.acquireID(); var hole = state.catalog.factoryElement(type, { id: holeID, name: NameGenerator.generateName('holes', state.catalog.getIn(['elements', type, 'info', 'title'])), type: type, offset: offset, line: lineID }, properties); state = state.setIn(['scene', 'layers', layerID, 'holes', holeID], hole); state = state.updateIn(['scene', 'layers', layerID, 'lines', lineID, 'holes'], function (holes) { return holes.push(holeID); }); return { updatedState: state, hole: hole }; } }, { key: 'select', value: function select(state, layerID, holeID) { state = Layer.select(state, layerID).updatedState; state = Layer.selectElement(state, layerID, 'holes', holeID).updatedState; return { updatedState: state }; } }, { key: 'remove', value: function remove(state, layerID, holeID) { var hole = state.getIn(['scene', 'layers', layerID, 'holes', holeID]); state = this.unselect(state, layerID, holeID).updatedState; state = Layer.removeElement(state, layerID, 'holes', holeID).updatedState; state = state.updateIn(['scene', 'layers', layerID, 'lines', hole.line, 'holes'], function (holes) { var index = holes.findIndex(function (ID) { return holeID === ID; }); return index !== -1 ? holes.remove(index) : holes; }); state.getIn(['scene', 'groups']).forEach(function (group) { return state = Group.removeElement(state, group.id, layerID, 'holes', holeID).updatedState; }); return { updatedState: state }; } }, { key: 'unselect', value: function unselect(state, layerID, holeID) { state = Layer.unselect(state, layerID, 'holes', holeID).updatedState; return { updatedState: state }; } }, { key: 'selectToolDrawingHole', value: function selectToolDrawingHole(state, sceneComponentType) { var snapElements = new List().withMutations(function (snapElements) { var _state$getIn = state.getIn(['scene', 'layers', state.scene.selectedLayer]), lines = _state$getIn.lines, vertices = _state$getIn.vertices; lines.forEach(function (line) { var _vertices$get = vertices.get(line.vertices.get(0)), x1 = _vertices$get.x, y1 = _vertices$get.y; var _vertices$get2 = vertices.get(line.vertices.get(1)), x2 = _vertices$get2.x, y2 = _vertices$get2.y; addLineSegmentSnap(snapElements, x1, y1, x2, y2, 20, 1, line.id); }); }); state = state.merge({ mode: MODE_DRAWING_HOLE, snapElements: snapElements, drawingSupport: Map({ type: sceneComponentType }) }); return { updatedState: state }; } }, { key: 'updateDrawingHole', value: function updateDrawingHole(state, layerID, x, y) { var catalog = state.catalog; //calculate snap and overwrite coords if needed //force snap to segment var snap = nearestSnap(state.snapElements, x, y, state.snapMask.merge({ SNAP_SEGMENT: true })); if (snap) { ; var _snap$point = snap.point; x = _snap$point.x; y = _snap$point.y; }var selectedHole = state.getIn(['scene', 'layers', layerID, 'selected', 'holes']).first(); if (snap) { var lineID = snap.snap.related.get(0); var vertices = state.getIn(['scene', 'layers', layerID, 'lines', lineID, 'vertices']); var _state$getIn2 = state.getIn(['scene', 'layers', layerID, 'vertices', vertices.get(0)]), x1 = _state$getIn2.x, y1 = _state$getIn2.y; var _state$getIn3 = state.getIn(['scene', 'layers', layerID, 'vertices', vertices.get(1)]), x2 = _state$getIn3.x, y2 = _state$getIn3.y; // I need min and max vertices on this line segment var minVertex = GeometryUtils.minVertex({ x: x1, y: y1 }, { x: x2, y: y2 }); var maxVertex = GeometryUtils.maxVertex({ x: x1, y: y1 }, { x: x2, y: y2 }); var width = catalog.factoryElement(state.drawingSupport.get('type')).properties.getIn(['width', 'length']); // Now I need min and max possible coordinates for the hole on the line. They depend on the width of the hole var lineLength = GeometryUtils.pointsDistance(x1, y1, x2, y2); var alpha = GeometryUtils.absAngleBetweenTwoPoints(x1, y1, x2, y2); var cosAlpha = GeometryUtils.cosWithThreshold(alpha, 0.0000001); var sinAlpha = GeometryUtils.sinWithThreshold(alpha, 0.0000001); var minLeftVertexHole = { x: minVertex.x + width / 2 * cosAlpha, y: minVertex.y + width / 2 * sinAlpha }; var maxRightVertexHole = { x: minVertex.x + lineLength * cosAlpha - width / 2 * cosAlpha, y: minVertex.y + lineLength * sinAlpha - width / 2 * sinAlpha }; var offset = void 0; if (x < minLeftVertexHole.x) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, minLeftVertexHole.x, minLeftVertexHole.y); } else if (x > maxRightVertexHole.x) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, maxRightVertexHole.x, maxRightVertexHole.y); } else { if (x === minLeftVertexHole.x && x === maxRightVertexHole.x) { if (y < minLeftVertexHole.y) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, minLeftVertexHole.x, minLeftVertexHole.y); offset = minVertex.x === x1 && minVertex.y === y1 ? offset : 1 - offset; } else if (y > maxRightVertexHole.y) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, maxRightVertexHole.x, maxRightVertexHole.y); offset = minVertex.x === x1 && minVertex.y === y1 ? offset : 1 - offset; } else { offset = GeometryUtils.pointPositionOnLineSegment(x1, y1, x2, y2, x, y); } } else { offset = GeometryUtils.pointPositionOnLineSegment(x1, y1, x2, y2, x, y); } } //if hole does exist, update if (selectedHole && snap) { state = state.mergeIn(['scene', 'layers', layerID, 'holes', selectedHole], { offset: offset, line: lineID }); //remove from old line ( if present ) var index = state.getIn(['scene', 'layers', layerID, 'lines']).findEntry(function (line) { return line.id !== lineID && line.get('holes').contains(selectedHole); }); if (index) { var removed = index[1].get('holes').filter(function (hl) { return hl !== selectedHole; }); state = state.setIn(['scene', 'layers', layerID, 'lines', index[0], 'holes'], removed); } //add to line var line_holes = state.getIn(['scene', 'layers', layerID, 'lines', lineID, 'holes']); if (!line_holes.contains(selectedHole)) { state = state.setIn(['scene', 'layers', layerID, 'lines', lineID, 'holes'], line_holes.push(selectedHole)); } } else if (!selectedHole && snap) { //if hole does not exist, create var _create = this.create(state, layerID, state.drawingSupport.get('type'), lineID, offset), stateH = _create.updatedState, hole = _create.hole; state = Hole.select(stateH, layerID, hole.id).updatedState; } } //i've lost the snap while trying to drop the hole else if (false && selectedHole) //think if enable { state = Hole.remove(state, layerID, selectedHole).updatedState; } return { updatedState: state }; } }, { key: 'endDrawingHole', value: function endDrawingHole(state, layerID, x, y) { state = this.updateDrawingHole(state, layerID, x, y).updatedState; state = Layer.unselectAll(state, layerID).updatedState; return { updatedState: state }; } }, { key: 'beginDraggingHole', value: function beginDraggingHole(state, layerID, holeID, x, y) { var layer = state.getIn(['scene', 'layers', layerID]); var hole = layer.getIn(['holes', holeID]); var line = layer.getIn(['lines', hole.line]); var v0 = layer.getIn(['vertices', line.vertices.get(0)]); var v1 = layer.getIn(['vertices', line.vertices.get(1)]); var snapElements = addLineSegmentSnap(List(), v0.x, v0.y, v1.x, v1.y, 9999999, 1, null); state = state.merge({ mode: MODE_DRAGGING_HOLE, snapElements: snapElements, draggingSupport: Map({ layerID: layerID, holeID: holeID, startPointX: x, startPointY: y }) }); return { updatedState: state }; } }, { key: 'updateDraggingHole', value: function updateDraggingHole(state, x, y) { //calculate snap and overwrite coords if needed //force snap to segment var snap = nearestSnap(state.snapElements, x, y, state.snapMask.merge({ SNAP_SEGMENT: true })); if (!snap) return state; var _state = state, draggingSupport = _state.draggingSupport, scene = _state.scene; var layerID = draggingSupport.get('layerID'); var holeID = draggingSupport.get('holeID'); var startPointX = draggingSupport.get('startPointX'); var startPointY = draggingSupport.get('startPointY'); var layer = state.getIn(['scene', 'layers', layerID]); var hole = layer.getIn(['holes', holeID]); var line = layer.getIn(['lines', hole.line]); var v0 = layer.getIn(['vertices', line.vertices.get(0)]); var v1 = layer.getIn(['vertices', line.vertices.get(1)]); // I need min and max vertices on this line segment var _snap$point2 = snap.point; x = _snap$point2.x; y = _snap$point2.y; var minVertex = GeometryUtils.minVertex(v0, v1); var maxVertex = GeometryUtils.maxVertex(v0, v1); // Now I need min and max possible coordinates for the hole on the line. They depend on the width of the hole var width = hole.properties.get('width').get('length'); var lineLength = GeometryUtils.pointsDistance(v0.x, v0.y, v1.x, v1.y); var alpha = Math.atan2(Math.abs(v1.y - v0.y), Math.abs(v1.x - v0.x)); var cosWithThreshold = function cosWithThreshold(alpha) { var cos = Math.cos(alpha); return cos < 0.0000001 ? 0 : cos; }; var sinWithThreshold = function sinWithThreshold(alpha) { var sin = Math.sin(alpha); return sin < 0.0000001 ? 0 : sin; }; var cosAlpha = cosWithThreshold(alpha); var sinAlpha = sinWithThreshold(alpha); var minLeftVertexHole = { x: minVertex.x + width / 2 * cosAlpha, y: minVertex.y + width / 2 * sinAlpha }; var maxRightVertexHole = { x: minVertex.x + lineLength * cosAlpha - width / 2 * cosAlpha, y: minVertex.y + lineLength * sinAlpha - width / 2 * sinAlpha }; // Now I need to verify if the snap vertex (with coordinates x and y) is on the line segment var offset = void 0; if (x < minLeftVertexHole.x) { // Snap point is previous the the line offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, minLeftVertexHole.x, minLeftVertexHole.y); } else { // Snap point is after the line or on the line if (x > maxRightVertexHole.x) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, maxRightVertexHole.x, maxRightVertexHole.y); } else if (x === minLeftVertexHole.x && x === maxRightVertexHole.x) { // I am on a vertical line, I need to check y coordinates if (y < minLeftVertexHole.y) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, minLeftVertexHole.x, minLeftVertexHole.y); offset = minVertex === v0 ? offset : 1 - offset; } else if (y > maxRightVertexHole.y) { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, maxRightVertexHole.x, maxRightVertexHole.y); offset = minVertex === v0 ? offset : 1 - offset; } else { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, x, y); offset = minVertex === v0 ? offset : 1 - offset; } } else { offset = GeometryUtils.pointPositionOnLineSegment(minVertex.x, minVertex.y, maxVertex.x, maxVertex.y, x, y); } } hole = hole.set('offset', offset); state = state.merge({ scene: scene.mergeIn(['layers', layerID, 'holes', holeID], hole) }); return { updatedState: state }; } }, { key: 'endDraggingHole', value: function endDraggingHole(state, x, y) { state = this.updateDraggingHole(state, x, y).updatedState; state = state.merge({ mode: MODE_IDLE }); return { updatedState: state }; } }, { key: 'setProperties', value: function setProperties(state, layerID, holeID, properties) { state = state.setIn(['scene', 'layers', layerID, 'holes', holeID, 'properties'], properties); return { updatedState: state }; } }, { key: 'setJsProperties', value: function setJsProperties(state, layerID, holeID, properties) { return this.setProperties(state, layerID, holeID, fromJS(properties)); } }, { key: 'updateProperties', value: function updateProperties(state, layerID, holeID, properties) { properties.forEach(function (v, k) { if (state.hasIn(['scene', 'layers', layerID, 'holes', holeID, 'properties', k])) state = state.mergeIn(['scene', 'layers', layerID, 'holes', holeID, 'properties', k], v); }); return { updatedState: state }; } }, { key: 'updateJsProperties', value: function updateJsProperties(state, layerID, holeID, properties) { return this.updateProperties(state, layerID, holeID, fromJS(properties)); } }, { key: 'setAttributes', value: function setAttributes(state, layerID, holeID, holesAttributes) { var hAttr = holesAttributes.toJS(); var offsetA = hAttr.offsetA, offsetB = hAttr.offsetB, offset = hAttr.offset; delete hAttr['offsetA']; delete hAttr['offsetB']; delete hAttr['offset']; var misc = new Map({ _unitA: offsetA._unit, _unitB: offsetB._unit }); state = state.mergeIn(['scene', 'layers', layerID, 'holes', holeID], fromJS(hAttr)).mergeDeepIn(['scene', 'layers', layerID, 'holes', holeID], new Map({ offset: offset, misc: misc })); return { updatedState: state }; } }]); return Hole; }(); export { Hole as default };