plot-plan-designer
Version:
Design Editor Tools with React.js + ant.design + fabric.js
280 lines (279 loc) • 15.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importStar(require("react"));
const prop_types_1 = __importDefault(require("prop-types"));
const antd_1 = require("antd");
const uuid_1 = require("uuid");
const classnames_1 = __importDefault(require("classnames"));
const i18next_1 = __importDefault(require("i18next"));
const flex_1 = require("../flex");
const Icon_1 = __importDefault(require("../icon/Icon"));
const Scrollbar_1 = __importDefault(require("../common/Scrollbar"));
const CommonButton_1 = __importDefault(require("../common/CommonButton"));
const common_1 = require("../common");
antd_1.notification.config({
top: 80,
duration: 2,
});
let ImageMapItems = /** @class */ (() => {
class ImageMapItems extends react_1.Component {
constructor() {
super(...arguments);
this.state = {
activeKey: [],
collapse: false,
textSearch: '',
descriptors: {},
filteredDescriptors: [],
svgModalVisible: false,
};
this.waitForCanvasRender = (canvas) => {
setTimeout(() => {
if (canvas) {
this.attachEventListener(canvas);
return;
}
const { canvasRef } = this.props;
this.waitForCanvasRender(canvasRef);
}, 5);
};
this.attachEventListener = (canvas) => {
canvas.canvas.wrapperEl.addEventListener('dragenter', this.events.onDragEnter, false);
canvas.canvas.wrapperEl.addEventListener('dragover', this.events.onDragOver, false);
canvas.canvas.wrapperEl.addEventListener('dragleave', this.events.onDragLeave, false);
canvas.canvas.wrapperEl.addEventListener('drop', this.events.onDrop, false);
};
this.detachEventListener = (canvas) => {
canvas.canvas.wrapperEl.removeEventListener('dragenter', this.events.onDragEnter);
canvas.canvas.wrapperEl.removeEventListener('dragover', this.events.onDragOver);
canvas.canvas.wrapperEl.removeEventListener('dragleave', this.events.onDragLeave);
canvas.canvas.wrapperEl.removeEventListener('drop', this.events.onDrop);
};
/* eslint-disable react/sort-comp, react/prop-types */
this.handlers = {
onAddItem: (item, centered) => {
const { canvasRef } = this.props;
if (canvasRef.handler.interactionMode === 'polygon') {
antd_1.message.info('Already drawing');
return;
}
const id = uuid_1.v4();
const option = Object.assign({}, item.option, { id });
if (item.option.superType === 'svg' && item.type === 'default') {
this.handlers.onSVGModalVisible(item.option);
return;
}
canvasRef.handler.add(option, centered);
},
onAddSVG: (option, centered) => {
const { canvasRef } = this.props;
canvasRef.handler.add(Object.assign(Object.assign({}, option), { type: 'svg', superType: 'svg', id: uuid_1.v4(), name: 'New SVG' }), centered);
this.handlers.onSVGModalVisible();
},
onDrawingItem: (item) => {
const { canvasRef } = this.props;
if (canvasRef.handler.interactionMode === 'polygon') {
antd_1.message.info('Already drawing');
return;
}
if (item.option.type === 'line') {
canvasRef.handler.drawingHandler.line.init();
}
else if (item.option.type === 'arrow') {
canvasRef.handler.drawingHandler.arrow.init();
}
else {
canvasRef.handler.drawingHandler.polygon.init();
}
},
onChangeActiveKey: (activeKey) => {
this.setState({
activeKey,
});
},
onCollapse: () => {
this.setState({
collapse: !this.state.collapse,
});
},
onSearchNode: (e) => {
const filteredDescriptors = this.handlers
.transformList()
.filter((descriptor) => descriptor.name.toLowerCase().includes(e.target.value.toLowerCase()));
this.setState({
textSearch: e.target.value,
filteredDescriptors,
});
},
transformList: () => {
return Object.values(this.props.descriptors).reduce((prev, curr) => prev.concat(curr), []);
},
onSVGModalVisible: () => {
this.setState((prevState) => {
return {
svgModalVisible: !prevState.svgModalVisible,
};
});
},
};
this.events = {
onDragStart: (e, item) => {
this.item = item;
const { target } = e;
target.classList.add('dragging');
},
onDragOver: (e) => {
if (e.preventDefault) {
e.preventDefault();
}
e.dataTransfer.dropEffect = 'copy';
return false;
},
onDragEnter: (e) => {
const { target } = e;
target.classList.add('over');
},
onDragLeave: (e) => {
const { target } = e;
target.classList.remove('over');
},
onDrop: (e) => {
e = e || window.event;
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
const { layerX, layerY } = e;
const dt = e.dataTransfer;
if (dt.types.length && dt.types[0] === 'Files') {
const { files } = dt;
Array.from(files).forEach((file) => {
file.uid = uuid_1.v4();
const { type } = file;
if (type === 'image/png' || type === 'image/jpeg' || type === 'image/jpg') {
const item = {
option: {
type: 'image',
file,
left: layerX,
top: layerY,
},
};
this.handlers.onAddItem(item, false);
}
else {
antd_1.notification.warn({
message: 'Not supported file type',
});
}
});
return false;
}
const option = Object.assign({}, this.item.option, { left: layerX, top: layerY });
const newItem = Object.assign({}, this.item, { option });
this.handlers.onAddItem(newItem, false);
return false;
},
onDragEnd: (e) => {
this.item = null;
e.target.classList.remove('dragging');
},
};
this.renderItems = (items) => {
return (react_1.default.createElement(flex_1.Flex, { flexWrap: "wrap", flexDirection: "column", style: { width: '100%' } }, items.map((item) => this.renderItem(item))));
};
this.renderItem = (item, centered) => item.type === 'drawing' ? (react_1.default.createElement("div", { key: item.name, draggable: true, onClick: (e) => this.handlers.onDrawingItem(item), className: "rde-editor-items-item", style: { justifyContent: this.state.collapse ? 'center' : null } },
react_1.default.createElement("span", { className: "rde-editor-items-item-icon" },
react_1.default.createElement(Icon_1.default, { name: item.icon.name, prefix: item.icon.prefix, style: item.icon.style })),
this.state.collapse ? null : react_1.default.createElement("div", { className: "rde-editor-items-item-text" }, item.trans ? i18next_1.default.t(`imagemap.descriptors.${item.trans}`) : item.name))) : (react_1.default.createElement("div", { key: item.name, draggable: true, onClick: (e) => this.handlers.onAddItem(item, centered), onDragStart: (e) => this.events.onDragStart(e, item), onDragEnd: (e) => this.events.onDragEnd(e, item), className: "rde-editor-items-item", style: { justifyContent: this.state.collapse ? 'center' : null } },
react_1.default.createElement("span", { className: "rde-editor-items-item-icon" },
react_1.default.createElement(Icon_1.default, { name: item.icon.name, prefix: item.icon.prefix, style: item.icon.style })),
this.state.collapse ? null : react_1.default.createElement("div", { className: "rde-editor-items-item-text" }, item.trans ? i18next_1.default.t(`imagemap.descriptors.${item.trans}`) : item.name)));
}
componentDidMount() {
const { canvasRef } = this.props;
this.waitForCanvasRender(canvasRef);
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (JSON.stringify(this.props.descriptors) !== JSON.stringify(nextProps.descriptors)) {
const descriptors = Object.keys(nextProps.descriptors).reduce((prev, key) => {
return prev.concat(nextProps.descriptors[key]);
}, []);
this.setState({
descriptors,
});
}
}
shouldComponentUpdate(nextProps, nextState) {
if (JSON.stringify(this.state.descriptors) !== JSON.stringify(nextState.descriptors)) {
return true;
}
else if (JSON.stringify(this.state.filteredDescriptors) !== JSON.stringify(nextState.filteredDescriptors)) {
return true;
}
else if (this.state.textSearch !== nextState.textSearch) {
return true;
}
else if (JSON.stringify(this.state.activeKey) !== JSON.stringify(nextState.activeKey)) {
return true;
}
else if (this.state.collapse !== nextState.collapse) {
return true;
}
else if (this.state.svgModalVisible !== nextState.svgModalVisible) {
return true;
}
return false;
}
componentWillUnmount() {
const { canvasRef } = this.props;
this.detachEventListener(canvasRef);
}
render() {
const { descriptors } = this.props;
const { collapse, textSearch, filteredDescriptors, activeKey, svgModalVisible, svgOption } = this.state;
const className = classnames_1.default('rde-editor-items', {
minimize: collapse,
});
return (react_1.default.createElement("div", { className: className },
react_1.default.createElement(flex_1.Flex, { flex: "1", flexDirection: "column", style: { height: '100%' } },
react_1.default.createElement(flex_1.Flex, { justifyContent: "center", alignItems: "center", style: { height: 40 } },
react_1.default.createElement(CommonButton_1.default, { icon: collapse ? 'angle-double-right' : 'angle-double-left', shape: "circle", className: "rde-action-btn", style: { margin: '0 4px' }, onClick: this.handlers.onCollapse, tooltipTitle: i18next_1.default.t('action.collapse') }),
collapse ? null : (react_1.default.createElement(antd_1.Input, { style: { margin: '8px' }, placeholder: i18next_1.default.t('action.search-list'), onChange: this.handlers.onSearchNode, value: textSearch, allowClear: true }))),
react_1.default.createElement(Scrollbar_1.default, null,
react_1.default.createElement(flex_1.Flex, { flex: "1", style: { overflowY: 'hidden' } }, (textSearch.length && this.renderItems(filteredDescriptors)) ||
(collapse ? (react_1.default.createElement(flex_1.Flex, { flexWrap: "wrap", flexDirection: "column", style: { width: '100%' }, justifyContent: "center" }, this.handlers.transformList().map((item) => this.renderItem(item)))) : (react_1.default.createElement(antd_1.Collapse, { style: { width: '100%' }, bordered: false, activeKey: activeKey.length ? activeKey : Object.keys(descriptors), onChange: this.handlers.onChangeActiveKey }, Object.keys(descriptors).map((key) => (react_1.default.createElement(antd_1.Collapse.Panel, { key: key, header: i18next_1.default.t(`imagemap.descriptors.${key.toLowerCase()}`), showArrow: !collapse }, this.renderItems(descriptors[key])))))))))),
react_1.default.createElement(common_1.SVGModal, { visible: svgModalVisible, onOk: this.handlers.onAddSVG, onCancel: this.handlers.onSVGModalVisible, option: svgOption })));
}
}
ImageMapItems.propTypes = {
canvasRef: prop_types_1.default.any,
descriptors: prop_types_1.default.object,
};
return ImageMapItems;
})();
exports.default = ImageMapItems;