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
JavaScript
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
};