UNPKG

react-planner

Version:

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

431 lines (362 loc) 13.1 kB
import React from 'react'; import PropTypes from 'prop-types'; import { ReactSVGPanZoom, TOOL_NONE, TOOL_PAN, TOOL_ZOOM_IN, TOOL_ZOOM_OUT, TOOL_AUTO } from 'react-svg-pan-zoom'; import * as constants from '../../constants'; import State from './state'; import * as SharedStyle from '../../shared-style'; import { RulerX, RulerY } from './export'; function mode2Tool(mode) { switch (mode) { case constants.MODE_2D_PAN: return TOOL_PAN; case constants.MODE_2D_ZOOM_IN: return TOOL_ZOOM_IN; case constants.MODE_2D_ZOOM_OUT: return TOOL_ZOOM_OUT; case constants.MODE_IDLE: return TOOL_AUTO; default: return TOOL_NONE; } } function mode2PointerEvents(mode) { switch (mode) { case constants.MODE_DRAWING_LINE: case constants.MODE_DRAWING_HOLE: case constants.MODE_DRAWING_ITEM: case constants.MODE_DRAGGING_HOLE: case constants.MODE_DRAGGING_ITEM: case constants.MODE_DRAGGING_LINE: case constants.MODE_DRAGGING_VERTEX: return { pointerEvents: 'none' }; default: return {}; } } function mode2Cursor(mode) { switch (mode) { case constants.MODE_DRAGGING_HOLE: case constants.MODE_DRAGGING_LINE: case constants.MODE_DRAGGING_VERTEX: case constants.MODE_DRAGGING_ITEM: return { cursor: 'move' }; case constants.MODE_ROTATING_ITEM: return { cursor: 'ew-resize' }; case constants.MODE_WAITING_DRAWING_LINE: case constants.MODE_DRAWING_LINE: return { cursor: 'crosshair' }; default: return { cursor: 'default' }; } } function mode2DetectAutopan(mode) { switch (mode) { case constants.MODE_DRAWING_LINE: case constants.MODE_DRAGGING_LINE: case constants.MODE_DRAGGING_VERTEX: case constants.MODE_DRAGGING_HOLE: case constants.MODE_DRAGGING_ITEM: case constants.MODE_DRAWING_HOLE: case constants.MODE_DRAWING_ITEM: return true; default: return false; } } function extractElementData(node) { while (!node.attributes.getNamedItem('data-element-root') && node.tagName !== 'svg') { node = node.parentNode; } if (node.tagName === 'svg') return null; return { part: node.attributes.getNamedItem('data-part') ? node.attributes.getNamedItem('data-part').value : undefined, layer: node.attributes.getNamedItem('data-layer').value, prototype: node.attributes.getNamedItem('data-prototype').value, selected: node.attributes.getNamedItem('data-selected').value === 'true', id: node.attributes.getNamedItem('data-id').value }; } export default function Viewer2D(_ref, _ref2) { var state = _ref.state, width = _ref.width, height = _ref.height; var viewer2DActions = _ref2.viewer2DActions, linesActions = _ref2.linesActions, holesActions = _ref2.holesActions, verticesActions = _ref2.verticesActions, itemsActions = _ref2.itemsActions, areaActions = _ref2.areaActions, projectActions = _ref2.projectActions, catalog = _ref2.catalog; var viewer2D = state.viewer2D, mode = state.mode, scene = state.scene; var layerID = scene.selectedLayer; var mapCursorPosition = function mapCursorPosition(_ref3) { var x = _ref3.x, y = _ref3.y; return { x: x, y: -y + scene.height }; }; var onMouseMove = function onMouseMove(viewerEvent) { //workaround that allow imageful component to work var evt = new Event('mousemove-planner-event'); evt.viewerEvent = viewerEvent; document.dispatchEvent(evt); var _mapCursorPosition = mapCursorPosition(viewerEvent), x = _mapCursorPosition.x, y = _mapCursorPosition.y; projectActions.updateMouseCoord({ x: x, y: y }); switch (mode) { case constants.MODE_DRAWING_LINE: linesActions.updateDrawingLine(x, y, state.snapMask); break; case constants.MODE_DRAWING_HOLE: holesActions.updateDrawingHole(layerID, x, y); break; case constants.MODE_DRAWING_ITEM: itemsActions.updateDrawingItem(layerID, x, y); break; case constants.MODE_DRAGGING_HOLE: holesActions.updateDraggingHole(x, y); break; case constants.MODE_DRAGGING_LINE: linesActions.updateDraggingLine(x, y, state.snapMask); break; case constants.MODE_DRAGGING_VERTEX: verticesActions.updateDraggingVertex(x, y, state.snapMask); break; case constants.MODE_DRAGGING_ITEM: itemsActions.updateDraggingItem(x, y); break; case constants.MODE_ROTATING_ITEM: itemsActions.updateRotatingItem(x, y); break; } viewerEvent.originalEvent.stopPropagation(); }; var onMouseDown = function onMouseDown(viewerEvent) { var event = viewerEvent.originalEvent; //workaround that allow imageful component to work var evt = new Event('mousedown-planner-event'); evt.viewerEvent = viewerEvent; document.dispatchEvent(evt); var _mapCursorPosition2 = mapCursorPosition(viewerEvent), x = _mapCursorPosition2.x, y = _mapCursorPosition2.y; if (mode === constants.MODE_IDLE) { var elementData = extractElementData(event.target); if (!elementData || !elementData.selected) return; switch (elementData.prototype) { case 'lines': linesActions.beginDraggingLine(elementData.layer, elementData.id, x, y, state.snapMask); break; case 'vertices': verticesActions.beginDraggingVertex(elementData.layer, elementData.id, x, y, state.snapMask); break; case 'items': if (elementData.part === 'rotation-anchor') itemsActions.beginRotatingItem(elementData.layer, elementData.id, x, y);else itemsActions.beginDraggingItem(elementData.layer, elementData.id, x, y); break; case 'holes': holesActions.beginDraggingHole(elementData.layer, elementData.id, x, y); break; default: break; } } event.stopPropagation(); }; var onMouseUp = function onMouseUp(viewerEvent) { var event = viewerEvent.originalEvent; var evt = new Event('mouseup-planner-event'); evt.viewerEvent = viewerEvent; document.dispatchEvent(evt); var _mapCursorPosition3 = mapCursorPosition(viewerEvent), x = _mapCursorPosition3.x, y = _mapCursorPosition3.y; switch (mode) { case constants.MODE_IDLE: var elementData = extractElementData(event.target); if (elementData && elementData.selected) return; switch (elementData ? elementData.prototype : 'none') { case 'areas': areaActions.selectArea(elementData.layer, elementData.id); break; case 'lines': linesActions.selectLine(elementData.layer, elementData.id); break; case 'holes': holesActions.selectHole(elementData.layer, elementData.id); break; case 'items': itemsActions.selectItem(elementData.layer, elementData.id); break; case 'none': projectActions.unselectAll(); break; } break; case constants.MODE_WAITING_DRAWING_LINE: linesActions.beginDrawingLine(layerID, x, y, state.snapMask); break; case constants.MODE_DRAWING_LINE: linesActions.endDrawingLine(x, y, state.snapMask); linesActions.beginDrawingLine(layerID, x, y, state.snapMask); break; case constants.MODE_DRAWING_HOLE: holesActions.endDrawingHole(layerID, x, y); break; case constants.MODE_DRAWING_ITEM: itemsActions.endDrawingItem(layerID, x, y); break; case constants.MODE_DRAGGING_LINE: linesActions.endDraggingLine(x, y, state.snapMask); break; case constants.MODE_DRAGGING_VERTEX: verticesActions.endDraggingVertex(x, y, state.snapMask); break; case constants.MODE_DRAGGING_ITEM: itemsActions.endDraggingItem(x, y); break; case constants.MODE_DRAGGING_HOLE: holesActions.endDraggingHole(x, y); break; case constants.MODE_ROTATING_ITEM: itemsActions.endRotatingItem(x, y); break; } event.stopPropagation(); }; var onChangeValue = function onChangeValue(value) { projectActions.updateZoomScale(value.a); return viewer2DActions.updateCameraView(value); }; var onChangeTool = function onChangeTool(tool) { switch (tool) { case TOOL_NONE: projectActions.selectToolEdit(); break; case TOOL_PAN: viewer2DActions.selectToolPan(); break; case TOOL_ZOOM_IN: viewer2DActions.selectToolZoomIn(); break; case TOOL_ZOOM_OUT: viewer2DActions.selectToolZoomOut(); break; } }; var _state$get$toJS = state.get('viewer2D').toJS(), e = _state$get$toJS.e, f = _state$get$toJS.f, SVGWidth = _state$get$toJS.SVGWidth, SVGHeight = _state$get$toJS.SVGHeight; var rulerSize = 15; //px var rulerUnitPixelSize = 100; var rulerBgColor = SharedStyle.PRIMARY_COLOR.main; var rulerFnColor = SharedStyle.COLORS.white; var rulerMkColor = SharedStyle.SECONDARY_COLOR.main; var sceneWidth = SVGWidth || state.getIn(['scene', 'width']); var sceneHeight = SVGHeight || state.getIn(['scene', 'height']); var sceneZoom = state.zoom || 1; var rulerXElements = Math.ceil(sceneWidth / rulerUnitPixelSize) + 1; var rulerYElements = Math.ceil(sceneHeight / rulerUnitPixelSize) + 1; return React.createElement( 'div', { style: { margin: 0, padding: 0, display: 'grid', gridRowGap: '0', gridColumnGap: '0', gridTemplateColumns: rulerSize + 'px ' + (width - rulerSize) + 'px', gridTemplateRows: rulerSize + 'px ' + (height - rulerSize) + 'px', position: 'relative' } }, React.createElement('div', { style: { gridColumn: 1, gridRow: 1, backgroundColor: rulerBgColor } }), React.createElement( 'div', { style: { gridRow: 1, gridColumn: 2, position: 'relative', overflow: 'hidden' }, id: 'rulerX' }, sceneWidth ? React.createElement(RulerX, { unitPixelSize: rulerUnitPixelSize, zoom: sceneZoom, mouseX: state.mouse.get('x'), width: width - rulerSize, zeroLeftPosition: e || 0, backgroundColor: rulerBgColor, fontColor: rulerFnColor, markerColor: rulerMkColor, positiveUnitsNumber: rulerXElements, negativeUnitsNumber: 0 }) : null ), React.createElement( 'div', { style: { gridColumn: 1, gridRow: 2, position: 'relative', overflow: 'hidden' }, id: 'rulerY' }, sceneHeight ? React.createElement(RulerY, { unitPixelSize: rulerUnitPixelSize, zoom: sceneZoom, mouseY: state.mouse.get('y'), height: height - rulerSize, zeroTopPosition: sceneHeight * sceneZoom + f || 0, backgroundColor: rulerBgColor, fontColor: rulerFnColor, markerColor: rulerMkColor, positiveUnitsNumber: rulerYElements, negativeUnitsNumber: 0 }) : null ), React.createElement( ReactSVGPanZoom, { style: { gridColumn: 2, gridRow: 2 }, width: width - rulerSize, height: height - rulerSize, value: viewer2D.isEmpty() ? null : viewer2D.toJS(), onChangeValue: onChangeValue, tool: mode2Tool(mode), onChangeTool: onChangeTool, detectAutoPan: mode2DetectAutopan(mode), onMouseDown: onMouseDown, onMouseMove: onMouseMove, onMouseUp: onMouseUp, miniaturePosition: 'none', toolbarPosition: 'none' }, React.createElement( 'svg', { width: scene.width, height: scene.height }, React.createElement( 'defs', null, React.createElement( 'pattern', { id: 'diagonalFill', patternUnits: 'userSpaceOnUse', width: '4', height: '4', fill: '#FFF' }, React.createElement('rect', { x: '0', y: '0', width: '4', height: '4', fill: '#FFF' }), React.createElement('path', { d: 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2', style: { stroke: '#8E9BA2', strokeWidth: 1 } }) ) ), React.createElement( 'g', { style: Object.assign(mode2Cursor(mode), mode2PointerEvents(mode)) }, React.createElement(State, { state: state, catalog: catalog }) ) ) ) ); } Viewer2D.propTypes = { state: PropTypes.object.isRequired, width: PropTypes.number.isRequired, height: PropTypes.number.isRequired }; Viewer2D.contextTypes = { viewer2DActions: PropTypes.object.isRequired, linesActions: PropTypes.object.isRequired, holesActions: PropTypes.object.isRequired, verticesActions: PropTypes.object.isRequired, itemsActions: PropTypes.object.isRequired, areaActions: PropTypes.object.isRequired, projectActions: PropTypes.object.isRequired, catalog: PropTypes.object.isRequired };