From d565588d39bb3d77e034508072e9abce1bd8ea5f Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Fri, 23 Aug 2019 19:23:38 +0800 Subject: [PATCH 01/12] fix some bugs & add demo using fabric ui --- demo/app.tsx | 245 +++++++++++++++--------- demo/appStyle.ts | 143 ++++++++++++++ demo/index.scss | 13 +- demo/src/components/FlowContextMenu.tsx | 39 ++++ demo/src/components/FlowDetailPanel.tsx | 24 +++ demo/src/components/FlowItemPanel.tsx | 92 +++++++++ demo/src/components/FlowToolbar.tsx | 39 ++++ demo/src/index.ts | 4 + src/components/Command.tsx | 6 - src/components/ContextMenu.tsx | 29 ++- src/components/CreateMenu.tsx | 10 - src/components/CustomCommand.tsx | 3 + src/components/DetailPanel.tsx | 19 +- src/components/Flow.tsx | 2 +- src/components/Item.tsx | 38 ++-- src/components/Menu.tsx | 10 +- src/components/MxGraph.tsx | 101 +++++----- src/components/Panel.tsx | 22 +-- src/components/TextEditor.tsx | 4 +- src/components/ToolCommand.tsx | 12 +- src/components/WithNameProps.tsx | 37 ++++ src/components/WithPropsApi.tsx | 27 +-- src/context/ClipboardContext.ts | 15 +- src/context/MxGraphContext.ts | 2 +- src/settings/port.ts | 27 ++- src/types/action.ts | 87 ++++++--- src/types/mxGraph.ts | 12 ++ 27 files changed, 764 insertions(+), 298 deletions(-) create mode 100644 demo/appStyle.ts create mode 100644 demo/src/components/FlowContextMenu.tsx create mode 100644 demo/src/components/FlowDetailPanel.tsx create mode 100644 demo/src/components/FlowItemPanel.tsx create mode 100644 demo/src/components/FlowToolbar.tsx create mode 100644 demo/src/index.ts delete mode 100644 src/components/CreateMenu.tsx create mode 100644 src/components/WithNameProps.tsx diff --git a/demo/app.tsx b/demo/app.tsx index 32276a5..92fcd42 100644 --- a/demo/app.tsx +++ b/demo/app.tsx @@ -1,28 +1,21 @@ import * as React from "react"; import { hot } from "react-hot-loader"; +import * as Fabric from "office-ui-fabric-react/lib"; + +import { + FlowContextMenu, + FlowDetailPanel, + FlowItemPanel, + FlowToolbar, +} from "./src/index"; import { - CanvasMenu, - Command, CustomCommand, - ContextMenu, - EdgeMenu, Flow, - Item, - ItemPanel, - MxGraph, - VertexMenu, - ToolCommand, - Toolbar, + // ItemPanel, Minimap, - NodePanel, - EdgePanel, - CanvasPanel, - DetailPanel, - TextEditor, + MxGraph, RegisterNode, - PropsComponent, - PortPanel } from "../src/index"; import "./index.scss"; @@ -90,85 +83,149 @@ const data2 = { }], }; +const { + Stack, + Label, +} = Fabric; -const shortCutStyle = { - color: "silver", - fontSize: 10, -}; +import { + detailPanelStyles, + flowContainerStyles, + itemPanelStyles, + minimapStyles, + panelAndMinimapStyles, + stackItemStyles, + verticalGapStackTokens, + windowContainerStyles, +} from "./appStyle"; + + +class Demo extends React.PureComponent { + + public render(): React.ReactNode { + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); + } +} -const Demo = () => ( -
- - - - Rounded - Rounded2 - Rounded2 - - - - Copy Ctrl + C - Cut Ctrl + X - Paste Ctrl + V - undo Ctrl + Z - redo - zoomIn - zoomOut - delete select cell Backspace - fit - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// const Demo = () => ( +//
+// +// +// +// Rounded +// Rounded2 +// Rounded2 +// +// +// +// Copy Ctrl + C +// Cut Ctrl + X +// Paste Ctrl + V +// undo Ctrl + Z +// redo +// zoomIn +// zoomOut +// delete select cell Backspace +// fit +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +//
-); +// ); export const App = hot(module)(Demo); diff --git a/demo/appStyle.ts b/demo/appStyle.ts new file mode 100644 index 0000000..7d748ff --- /dev/null +++ b/demo/appStyle.ts @@ -0,0 +1,143 @@ + +import * as Fabric from "office-ui-fabric-react"; +const { + DefaultPalette, + mergeStyles, + getTheme, + mergeStyleSets, +} = Fabric; +import { IStackTokens } from "office-ui-fabric-react"; +export const toolbarTokens: IStackTokens = { + childrenGap: "sm8", + padding: "s" +}; + +export const toolbarStyles = { + root: { + borderStyle: "solid", + borderWidth: "1px", + borderColor: "#a0aeb2", + marginRight: "-1px", + marginBottom: "-1px", + } +}; + +const basicStyles = { + root: { + borderStyle: "solid", + borderWidth: "1px", + borderColor: "#a0aeb2", + marginRight: "-1px", + marginBottom: "-1px", + } +}; + +export const panelAndMinimapStyles = { + root: { + width: "16.67%", + borderStyle: "solid", + borderWidth: "1px", + borderColor: "#a0aeb2", + marginRight: "-1px", + marginBottom: "-1px", + height: "1000px", + } +}; + +export const itemPanelStyles = { + root: { + width: "16.67%", + borderStyle: "solid", + borderWidth: "1px", + borderColor: "#a0aeb2", + marginRight: "-1px", + marginBottom: "-1px", + } +}; + +export const flowContainerStyles = { + root: { + width: "66.67%", + borderStyle: "solid", + borderWidth: "1px", + borderColor: "#a0aeb2", + marginRight: "-1px", + marginBottom: "-1px", + } +} + +export const verticalGapStackTokens: IStackTokens = { + childrenGap: 10, + padding: 10, +}; + +export const stackItemStyles: IStackItemStyles = { + root: { + // background: DefaultPalette.themePrimary, + // color: DefaultPalette.white, + // padding: 5 + } +}; + +export const detailPanelStyles = { + root: { + height: "600px", + borderBottom: "1px", + borderBottomStyle: "solid", + borderBottomColor: "grey", + } +}; + +export const iconClass = mergeStyles({ + margin: '1 10px', + +}); + +export const minimapStyles = { + root: { + height: "30%", + } +}; + +// export const stackItemStyles = mergeStyles({ +// alignItems: 'center', +// background: DefaultPalette.neutralPrimary, +// color: DefaultPalette.white, +// display: 'flex', +// height: 30, +// justifyContent: "center", +// width: 60 +// }); + +export const theme = getTheme(); +export const headerAndFooterStyles: IRawStyle = { + lineHeight: 40, + paddingLeft: 16 +}; + +export const windowContainerStyles: IRawStyle = { + minHeigh: 800, + minWeight: 800, + Height: 1800, +} + +export const classNames = mergeStyleSets({ + header: [headerAndFooterStyles, theme.fonts.medium], + footer: [headerAndFooterStyles, theme.fonts.small], + name: { + display: 'inline-block', + overflow: 'hidden', + height: 24, + cursor: 'default', + padding: 8, + boxSizing: 'border-box', + verticalAlign: 'top', + background: 'none', + backgroundColor: 'transparent', + border: 'none', + paddingLeft: 32 + }, + button: { + border: 'none', + } +}); \ No newline at end of file diff --git a/demo/index.scss b/demo/index.scss index 46233a9..a56726b 100644 --- a/demo/index.scss +++ b/demo/index.scss @@ -41,16 +41,17 @@ table.mxPopupMenu tr { font-size: 4pt; } -body div.flow-container { - width: 600px; - height: 400px; - border-top: solid 1px #cccccc; - border-bottom: solid 1px #cccccc; -} +// body div.flow-container { +// width: 600px; +// height: 400px; +// border-top: solid 1px #cccccc; +// border-bottom: solid 1px #cccccc; +// } body div.minimap-container { width: 200px; height: 200px; + margin: 5px; border-top: solid 1px #6F6F6F; border-left: solid 1px #6F6F6F; border-right: solid 1px #6F6F6F; diff --git a/demo/src/components/FlowContextMenu.tsx b/demo/src/components/FlowContextMenu.tsx new file mode 100644 index 0000000..6750b2f --- /dev/null +++ b/demo/src/components/FlowContextMenu.tsx @@ -0,0 +1,39 @@ +import * as React from "react"; +import { + ContextMenu, + VertexMenu, + EdgeMenu, + CanvasMenu, + Command, +} from "../../../src/index"; + + +export const FlowContextMenu = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/demo/src/components/FlowDetailPanel.tsx b/demo/src/components/FlowDetailPanel.tsx new file mode 100644 index 0000000..9e73f3c --- /dev/null +++ b/demo/src/components/FlowDetailPanel.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import { + DetailPanel, + EdgePanel, + NodePanel, + PortPanel, + TextEditor, +} from "../../../src/index"; + +export const FlowDetailPanel = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/demo/src/components/FlowItemPanel.tsx b/demo/src/components/FlowItemPanel.tsx new file mode 100644 index 0000000..fae8142 --- /dev/null +++ b/demo/src/components/FlowItemPanel.tsx @@ -0,0 +1,92 @@ +import * as React from "react"; + +import { + Item, +} from "../../../src/index"; + +import * as Fabric from "office-ui-fabric-react"; + +const { + GroupedList, + DefaultButton, + FontIcon, + Label, +} = Fabric; + +import { createGroups, } from 'office-ui-fabric-react/lib/utilities/exampleData'; + +import { + iconClass, + classNames, +} from "../../appStyle"; + + +export class FlowItemPanel extends React.PureComponent { + private _items: object[] = [ + { + shape: "rounded", + size: "70*30", + model: { color: "#FA8C16", label: "Item 1", }, + }, { + shape: "rounded2", + size: "100*40", + model: { color: "#FA8C16", label: "Item 2", }, + }, { + shape: "ellipse", + size: "50*50", + model: { color: "#FA8C16", label: "Item 3", }, + }, + ]; + private _groups = createGroups(1, 1, 0, 3); + + public render(): JSX.Element { + return ( + + ); + } + + private onRenderCell(nestingDepth: number, item: IItemProps, itemIndex: number): JSX.Element { + return ( +
+ + + {item.shape} + + +
+ ); + } + + // tslint:disable-next-line: max-func-body-length + private onRenderHeader(props: IGroupHeaderProps): JSX.Element { + const toggleCollapse = (): void => { + props.onToggleCollapse!(props.group!); + }; + + return ( +
+ + + { + props.group.isCollapsed ? + : + + } + +
+ ); + } + + private onRenderFooter(props: IGroupFooterProps): JSX.Element { + // return
{props.group!.name}
; + return null; + } +} \ No newline at end of file diff --git a/demo/src/components/FlowToolbar.tsx b/demo/src/components/FlowToolbar.tsx new file mode 100644 index 0000000..40b124c --- /dev/null +++ b/demo/src/components/FlowToolbar.tsx @@ -0,0 +1,39 @@ +import * as React from "react"; + +import * as Fabric from "office-ui-fabric-react"; + +const { + Stack, + IconButton, + initializeIcons, +} = Fabric; + +import { + Toolbar, + ToolCommand, +} from "../../../src/index"; + +import { + toolbarStyles, + toolbarTokens, +} from "../../appStyle"; + +initializeIcons(); + +export const FlowToolbar = () => { + return ( + + + + + + + + + + + + + + ); +} diff --git a/demo/src/index.ts b/demo/src/index.ts new file mode 100644 index 0000000..791bcaf --- /dev/null +++ b/demo/src/index.ts @@ -0,0 +1,4 @@ +export * from "./components/FlowContextMenu"; +export * from "./components/FlowDetailPanel"; +export * from "./components/FlowItemPanel"; +export * from "./components/FlowToolbar"; \ No newline at end of file diff --git a/src/components/Command.tsx b/src/components/Command.tsx index f874c63..a6f1972 100644 --- a/src/components/Command.tsx +++ b/src/components/Command.tsx @@ -12,9 +12,6 @@ import { MenuItemContext, } from "../context/MenuContext"; -import { - actionType, -} from "../types/action"; export class Command extends React.PureComponent<{name: string; text?: string}> { constructor(props: {name: string; text?: string}) { @@ -26,9 +23,6 @@ export class Command extends React.PureComponent<{name: string; text?: string}> {(menuContext: IMenuItemContext) => { const { addItem } = menuContext; if (menuContext.enabled) { - if (this.props.name !== "separator" && actionType.indexOf(this.props.name) === -1) { - throw new Error("Menu Item Type Error"); - } addItem(this.props.name, this.props.text ? this.props.text : "default"); } return null; diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 0d8bfe5..175b883 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -56,44 +56,41 @@ export class ContextMenu extends React.PureComponent { {(value: IMxGraphContext) => { const { graph, - action, + actions, } = value; mxEvent.disableContextMenu(document.body); - if (graph && action) { + if (graph && actions) { graph.popupMenuHandler.autoExpand = true; graph.popupMenuHandler.factoryMethod = (menu, cell, _evt) => { const currentMenu: IMenu[] = this._getMenuFromCell(cell); if (currentMenu.length !== 0) { // tslint:disable-next-line: cyclomatic-complexity - currentMenu.map((item) => { + currentMenu.forEach((item) => { const text = item.text ? item.text : "default"; + const type = item.menuItemType; // tslint:disable-next-line: prefer-switch - if (item.menuItemType === "separator") { + if (type === "separator") { menu.addSeparator(); } else { - if (!action.hasOwnProperty(item.menuItemType)) { + if (!actions.hasOwnProperty(type)) { throw new Error("not be initialized in action"); } - const func = item.menuItemType === "paste" ? - action.paste.getFunc(menu.triggerX, menu.triggerY) : - action[item.menuItemType].func; - const menuItem = menu.addItem(text, null, func); + const menuItem = menu.addItem(text, null, () => { + actions[type].func({x: menu.triggerX, y: menu.triggerY}); + }); const td = menuItem.firstChild.nextSibling.nextSibling; const span = document.createElement("span"); span.style.color = "gray"; - const shortCutText = item.menuItemType === "paste" ? "Ctrl+V" : - item.menuItemType === "copy" ? "Ctrl+C" : - item.menuItemType === "cut" ? "Ctrl+X" : - item.menuItemType === "undo" ? "Ctrl+Z" : ""; + const shortCutText = actions[type].shortcuts ? actions[type].shortcuts[0] : ""; mxUtils.write(span, shortCutText); td.appendChild(span); // tslint:disable-next-line: prefer-switch - if (item.menuItemType === "copy" || item.menuItemType === "cut") { - this.addListener(menuItem, graph, copy, textInput); - } + // if (item.menuItemType === "copy" || item.menuItemType === "cut") { + // this.addListener(menuItem, graph, copy, textInput); + // } } }); diff --git a/src/components/CreateMenu.tsx b/src/components/CreateMenu.tsx deleted file mode 100644 index 357b879..0000000 --- a/src/components/CreateMenu.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import * as React from "react"; - -// tslint:disable-next-line: export-name -export function createMenu(MenuComponent, name): React.PureComponent { - return class extends React.PureComponent { - public render(): React.ReactNode { - return ; - } - }; -} diff --git a/src/components/CustomCommand.tsx b/src/components/CustomCommand.tsx index 900310f..ccb74b0 100644 --- a/src/components/CustomCommand.tsx +++ b/src/components/CustomCommand.tsx @@ -8,7 +8,9 @@ interface IProps { } class ACommand extends React.PureComponent { + public render(): React.ReactNode { + console.log("render"); const { propsAPI } = this.props; const { save, update, getSelected } = propsAPI; @@ -19,6 +21,7 @@ class ACommand extends React.PureComponent { execute(): void { const chart = save(); const selectedNodes = getSelected(); + console.log(selectedNodes); selectedNodes.map((node) => { update(node, {x : node.geometry.x + 2}); }); diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index aec786a..22f579e 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -4,7 +4,8 @@ import * as React from "react"; import * as mxGraphJs from "mxgraph-js"; const { - mxGraphSelectionModel + mxGraphSelectionModel, + mxEvent } = mxGraphJs; import { @@ -57,15 +58,10 @@ export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> { } private readonly _setListener = (graph: IMxGraph) => { - // tslint:disable-next-line: no-this-assignment - const that = this; - const selectChange = mxGraphSelectionModel.prototype.changeSelection ; - graph.getSelectionModel().changeSelection = function(): void { - selectChange.apply(this, arguments); - - that.setState({cells: graph.getSelectionCells()}); - }; + graph.getSelectionModel().addListener(mxEvent.CHANGE, (sender: any, evt: any) => { + this.setState({cells: graph.getSelectionCells()}); + }); } private readonly _getName = (graph: IMxGraph, cells?: ImxCell[]): string => { @@ -73,6 +69,11 @@ export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> { return "no selection"; } if (cells.length > 1) { + if (cells.map((cell) => +!graph.isPort(cell)) + .reduce((acc, cur) => (acc + cur)) === 1) { + return "vertex"; + } + return "multi"; // tslint:disable-next-line: prefer-switch } else if (cells.length === 1) { diff --git a/src/components/Flow.tsx b/src/components/Flow.tsx index 6052eaa..72043c0 100644 --- a/src/components/Flow.tsx +++ b/src/components/Flow.tsx @@ -48,7 +48,7 @@ export class Flow extends React.PureComponent { readData(graph, this.props.data); } return ( -
+
); }} diff --git a/src/components/Item.tsx b/src/components/Item.tsx index 07e696d..2737965 100644 --- a/src/components/Item.tsx +++ b/src/components/Item.tsx @@ -24,7 +24,7 @@ import { IMxGraph, } from "../types/mxGraph"; -interface IItem { +export interface IItemProps { shape: string; size?: string; model?: { @@ -33,32 +33,48 @@ interface IItem { }; } -export class Item extends React.PureComponent{ - public _insertVertex?: (parent, graph, node) => ImxCell; +export class Item extends React.PureComponent{ + public _insertVertex?: (parent: ImxCell, graph: IMxGraph, node: ICanvasNode) => ImxCell; private readonly _containerRef = React.createRef(); - constructor(props: IItem) { + private _graph?: IMxGraph; + constructor(props: IItemProps) { super(props); } public render(): React.ReactNode { + return ( -
+
+ {this.props.children} {(context: IMxGraphContext) => { const { graph, insertVertex } = context; const container = this._containerRef.current; - - if (!graph || !container) { + if (graph && insertVertex) { + this._graph = graph; + this._insertVertex = insertVertex; + } else { return null; } - this._insertVertex = insertVertex; - this.addToolbarItem(graph, container); + if (container) { + this.addToolbarItem(graph, container); + } return null; }} - {this.props.children}
); } + public componentDidMount = () => { + + if (this._graph && this._containerRef.current) { + this.addToolbarItem(this._graph, this._containerRef.current); + } + } + + public componentDidUpdate = () => { + console.log("item did update"); + } + private readonly addVertex = (text: string, width: string, height: string, style: string): ImxCell => { const vertex = new mxCell(text, new mxGeometry(0, 0, width, height), style); vertex.setVertex(true); @@ -81,7 +97,7 @@ export class Item extends React.PureComponent{ } - private readonly addToolbarItem = (graph: IMxGraph, elt: HTMLDivElement): void => { + private readonly addToolbarItem = (graph: IMxGraph, elt: HTMLDivElement | HTMLSpanElement): void => { const size = this.props.size ? this.props.size.split("*") : [100, 70]; const dragElt = document.createElement("div"); dragElt.style.border = "dashed black 1px"; diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx index 23bd643..aff2bfd 100644 --- a/src/components/Menu.tsx +++ b/src/components/Menu.tsx @@ -7,8 +7,8 @@ import { } from "../context/MenuContext"; import { - createMenu, -} from "./CreateMenu"; + withNameProps, +} from "./WithNameProps"; export class Menu extends React.PureComponent<{name: string}> { public menu: Array<{ @@ -39,6 +39,6 @@ export class Menu extends React.PureComponent<{name: string}> { } } -export const VertexMenu = createMenu(Menu, "vertex"); -export const EdgeMenu = createMenu(Menu, "edge"); -export const CanvasMenu = createMenu(Menu, "canvas"); +export const VertexMenu = withNameProps(Menu, "vertex"); +export const EdgeMenu = withNameProps(Menu, "edge"); +export const CanvasMenu = withNameProps(Menu, "canvas"); diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index 20dcc53..a0eeb09 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -10,7 +10,7 @@ import { MxGraphContext } from "../context/MxGraphContext"; import { init } from "../settings/init"; -import { IMxActions, initAction } from "../types/action"; +import { IMxActions, initActions } from "../types/action"; import { customShortcutDictionary, ICustomCommand } from "../types/command"; import { ICanvasData, ICanvasEdge, ICanvasNode } from "../types/flow"; import { @@ -19,6 +19,7 @@ import { IMxGraph, IMxState, IMxUndoManager, + IKeyHandler, } from "../types/mxGraph"; import { ICustomShape, } from "../types/shapes"; @@ -48,9 +49,10 @@ export class MxGraph extends React.PureComponent<{}, IState> { private undoManager: IMxUndoManager; private mouseX: number; private mouseY: number; - private action: IMxActions; + private actions: IMxActions; private readonly customShape: ICustomShape[]; private readonly customCommand: ICustomCommand[]; + private keyHandler: IKeyHandler; private _firstUpdate: boolean; constructor(props: {}) { @@ -73,10 +75,11 @@ export class MxGraph extends React.PureComponent<{}, IState> { const rubberband = new mxRubberband(graph); this.undoManager = new mxUndoManager(); // tslint:disable-next-line: deprecation - this.action = initAction(graph, this.context, this.undoManager); + this.actions = initActions(graph, this.context, this.undoManager); + this.keyHandler = this.setKeyHandler(graph); + this.addUndoEvent(graph); this.addCopyEvent(graph); - this.setKeyHandler(graph); this.setMouseEvent(graph); this.registerNode(graph); @@ -94,8 +97,8 @@ export class MxGraph extends React.PureComponent<{}, IState> { graph.getView() .addListener(mxEvent.UNDO, listener); } - // tslint:disable-next-line: max-func-body-length - public addCopyEvent = (graph: IMxGraph) => { // , textInput: HTMLTextAreaElement, copy: ICopy) => { + + public addCopyEvent = (graph: IMxGraph) => { // tslint:disable-next-line: deprecation const { copy, textInput } = this.context; copy.gs = graph.gridSize; @@ -103,50 +106,34 @@ export class MxGraph extends React.PureComponent<{}, IState> { // For jest // tslint:disable-next-line: strict-type-predicates - if (graph.container !== undefined) { + if (graph.container) { mxEvent.addListener(graph.container, "mousemove", mxUtils.bind(this, (evt: MouseEvent) => { this.mouseX = evt.offsetX; this.mouseY = evt.offsetY; })); + mxEvent.addListener(graph.container, "mouseenter", mxUtils.bind(this, (evt: MouseEvent) => { + graph.setEnabled(true); + })); + mxEvent.addListener(graph.container, "mouseleave", mxUtils.bind(this, (evt: MouseEvent) => { + graph.setEnabled(false); + })); } - // tslint:disable-next-line: cyclomatic-complexity - mxEvent.addListener(document, "keydown", (evt: KeyboardEvent) => { - const source = mxEvent.getSource(evt); - if (graph.isEnabled() && !graph.isMouseDown && !graph.isEditing() && source.nodeName !== "INPUT") { - // tslint:disable-next-line: deprecation - if (evt.keyCode === 224 /* FF */ || (!mxClient.IS_MAC && evt.keyCode === 17 /* Control */) || (mxClient.IS_MAC && evt.keyCode === 91 /* Meta */)) { - // tslint:disable-next-line: deprecation - this.context.beforeUsingClipboard(graph, copy, textInput); - } - } + this.keyHandler.bindControlKey(67, () => { + this.actions.copy.func(); }); - mxEvent.addListener(document, "keyup", (evt: KeyboardEvent) => { - // tslint:disable-next-line: deprecation - if (copy.restoreFocus && (evt.keyCode === 224 || evt.keyCode === 17 || evt.keyCode === 91)) { - // tslint:disable-next-line: deprecation - this.context.afterUsingClipboard(graph, copy, textInput); - } + this.keyHandler.bindControlKey(88, () => { + this.actions.cut.func(); }); - mxEvent.addListener(textInput, "copy", mxUtils.bind(this, (_evt: ClipboardEvent) => { - // tslint:disable-next-line: deprecation - this.context.copyFunc(graph, copy, textInput); - })); - - mxEvent.addListener(textInput, "cut", mxUtils.bind(this, (_evt: ClipboardEvent) => { - // tslint:disable-next-line: deprecation - this.context.cutFunc(graph, copy, textInput); - })); - - mxEvent.addListener(textInput, "paste", (evt: ClipboardEvent) => { - // tslint:disable-next-line: deprecation - this.context.pasteFunc(evt, graph, copy, textInput, this.mouseX, this.mouseY); + this.keyHandler.bindControlKey(86, () => { + this.actions.pasteHere.func({ x: this.mouseX, y: this.mouseY }); }); } + public componentWillMount(): void { if (!mxClient.isBrowserSupported()) { mxUtils.error("Browser is not supported!", 200, false); @@ -164,7 +151,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { value={{ graph: this.state.graph, setGraph: this.setGraph, - action: this.action, + actions: this.actions, customShape: this.customShape, customCommand: this.customCommand, readData: this.readData, @@ -185,15 +172,15 @@ export class MxGraph extends React.PureComponent<{}, IState> { textInput.value = " "; } - private readonly setKeyHandler = (graph: IMxGraph): void => { + private readonly setKeyHandler = (graph: IMxGraph): IKeyHandler => { const keyHandler = new mxKeyHandler(graph); - keyHandler.bindControlKey(90, (evt) => { - this.action.undo.func(); + keyHandler.bindControlKey(90, (evt: KeyboardEvent) => { + this.actions.undo.func(); }); - keyHandler.bindKey(8, (evt) => { - this.action.deleteCell.func(); + keyHandler.bindKey(8, (evt: KeyboardEvent) => { + this.actions.deleteCell.func(); }); - keyHandler.bindKey(9, (evt) => { + keyHandler.bindKey(9, (evt: KeyboardEvent) => { if (graph.isEnabled()) { if (graph.isEditing()) { graph.stopEditing(false); @@ -201,6 +188,10 @@ export class MxGraph extends React.PureComponent<{}, IState> { graph.selectCell(true); } }); + keyHandler.bindShiftKey(9, () => { if (graph.isEnabled()) { graph.selectPreviousCell(); } }); // Shift+Tab + keyHandler.bindControlKey(9, () => { if (graph.isEnabled()) { graph.selectParentCell(); } }); // Ctrl+Tab + keyHandler.bindControlShiftKey(9, () => { if (graph.isEnabled()) { graph.selectChildCell(); } }); // Ctrl+Shift+Tab + return keyHandler; } private readonly addCustomKeyEvent = (graph: IMxGraph, func: () => void, key: string): void => { @@ -230,13 +221,8 @@ export class MxGraph extends React.PureComponent<{}, IState> { const config = command.config; if (customShortcutDictionary.hasOwnProperty(command.name) && customShortcutDictionary[command.name] && config.enable) { // tslint:disable-next-line: no-unbound-method - this.addAction(this.action, command.name, config.execute); - if (config.shortcutCodes) { - config.shortcutCodes.forEach((shortcutCode) => { - // tslint:disable-next-line: no-unbound-method - this.addCustomKeyEvent(graph, config.execute, shortcutCode); - }); - } + this.addAction(graph, this.actions, command.name, config.execute, config.shortcutCodes); + console.log(command); } }); } @@ -398,8 +384,17 @@ export class MxGraph extends React.PureComponent<{}, IState> { } - private readonly addAction = (action: IMxActions, name: string, func: () => void): void => { - action[name] = new Object(); - action[name].func = func; + private readonly addAction = (graph: IMxGraph, actions: IMxActions, name: string, func: () => void, shortcuts?: string[]): void => { + actions[name] = new Object(); + actions[name].func = func; + if (!shortcuts) { return; } + actions[name].shortcuts = shortcuts; + shortcuts.forEach((shortcut) => { + mxEvent.addListener(document, "keydown", (event: KeyboardEvent) => { + if (graph.isEnabled() && !graph.isMouseDown && !graph.isEditing() && event.key === shortcut) { + func(); + } + }); + }); } } diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index f0a0e71..7667c04 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -22,7 +22,7 @@ class Panel extends React.PureComponent<{name: string}> { } return ( -
+
{`${name} panel:`} {this.props.children}
@@ -36,16 +36,10 @@ class Panel extends React.PureComponent<{name: string}> { } } -function createPanel(PanelComponent, name: string): React.PureComponent { - // tslint:disable-next-line: max-classes-per-file - return class extends React.PureComponent { - public render(): React.ReactNode { - return ; - } - }; -} - -export const NodePanel = createPanel(Panel, "vertex"); -export const EdgePanel = createPanel(Panel, "edge"); -export const CanvasPanel = createPanel(Panel, "canvas"); -export const PortPanel = createPanel(Panel, "port"); +import { + withNameProps +} from "./WithNameProps"; +export const NodePanel = withNameProps(Panel, "vertex"); +export const EdgePanel = withNameProps(Panel, "edge"); +export const CanvasPanel = withNameProps(Panel, "canvas"); +export const PortPanel = withNameProps(Panel, "port"); diff --git a/src/components/TextEditor.tsx b/src/components/TextEditor.tsx index 096af4a..3387c78 100644 --- a/src/components/TextEditor.tsx +++ b/src/components/TextEditor.tsx @@ -49,7 +49,9 @@ export class TextEditor extends React.PureComponent<{}, { value: string }> { this._first = false; } return ( - +
+ +
); } }} diff --git a/src/components/ToolCommand.tsx b/src/components/ToolCommand.tsx index 80628fa..8cb614a 100644 --- a/src/components/ToolCommand.tsx +++ b/src/components/ToolCommand.tsx @@ -18,19 +18,17 @@ export class ToolCommand extends React.PureComponent<{ name: string; text?: stri
{this.props.children} {(value: IMxGraphContext) => { - const { graph, action } = value; + const { graph, actions } = value; const container = this._containerRef.current; - if (!graph || !container || !action) { + if (!graph || !container || !actions) { return null; } const itemType = this.props.name; - const func = itemType === "paste" ? - action.paste.getFunc() : - action[itemType].func; - // this.addListener(container, graph, clipboard); do not know if there will be influence - container.addEventListener("click", (_evt) => { func(); }); + container.addEventListener("click", (_evt) => { + actions[itemType].func(); + }); return null; }} diff --git a/src/components/WithNameProps.tsx b/src/components/WithNameProps.tsx new file mode 100644 index 0000000..d0fe914 --- /dev/null +++ b/src/components/WithNameProps.tsx @@ -0,0 +1,37 @@ +import * as React from "react"; + +// // tslint:disable-next-line: export-name +// export function createMenu(MenuComponent, name): React.PureComponent { +// return class extends React.PureComponent { +// public render(): React.ReactNode { +// return ; +// } +// }; +// } + +// const withNameProps =

(PanelComponent: React.ComponentType

, name: string) => { +// return ( +// class WithNameProps extends React.PureComponent

{ +// public render(): React.ReactNode { +// return ; +// } +// }; +// ) +// } + +export interface InjectedCounterProps { + name: string; +} + +export const withNameProps = (Component: any, name: string) => + class MakeCounter extends React.PureComponent { + + public render(): JSX.Element { + return ( + + ); + } + }; diff --git a/src/components/WithPropsApi.tsx b/src/components/WithPropsApi.tsx index 88c6af9..f35d3c1 100644 --- a/src/components/WithPropsApi.tsx +++ b/src/components/WithPropsApi.tsx @@ -9,7 +9,6 @@ import { ICanvasNode, } from "../types/flow"; import { ImxCell, IMxGraph } from "../types/mxGraph"; -import { shapeDictionary } from "../types/shapes"; const { mxConstants, @@ -41,22 +40,20 @@ export function withPropsApi(WrappedComponent): React.PureComponent { {(value: IMxGraphContext) => { const { graph, - action, + actions, readData, insertVertex, insertEdge, } = value; - if (graph && action) { + if (graph && actions) { + const model = graph.getModel(); const propsAPI: IPropsAPI = { graph, executeCommand: (command) => { - if (!action.hasOwnProperty(command)) { + if (!actions.hasOwnProperty(command)) { throw new Error("this command is not initialized in action"); } - const func = command === "paste" ? - action.paste.getFunc() : - action[command].func; - func(); + actions[command].func(); }, find: (id) => { return graph.getModel() @@ -112,19 +109,17 @@ export function withPropsApi(WrappedComponent): React.PureComponent { } }, update: (cell: ImxCell, model: ICanvasEdge | ICanvasNode) => { - if (!cell) { + if (!cell || graph.isPort(cell) ) { return; } const { x, y, size, label, color } = model; const bounds = { x: x ? x : cell.geometry.x, y: y ? y : cell.geometry.y, - width: (size && size[0]) ? size[0] : cell.geometry.width, - height: (size && size[1]) ? size[1] : cell.geometry.height, + width: size ? size[0] : cell.geometry.width, + height: size ? size[1] : cell.geometry.height, }; - graph - .getModel() - .beginUpdate(); + graph.model.beginUpdate(); try { // resize graph.resizeCell(cell, bounds); @@ -139,9 +134,7 @@ export function withPropsApi(WrappedComponent): React.PureComponent { graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, color, [cell]); } } finally { - graph - .getModel() - .endUpdate(); + graph.model.endUpdate(); } }, remove: (cell: ImxCell) => { diff --git a/src/context/ClipboardContext.ts b/src/context/ClipboardContext.ts index 7862b30..34fe504 100644 --- a/src/context/ClipboardContext.ts +++ b/src/context/ClipboardContext.ts @@ -10,7 +10,7 @@ const { mxCodec, } = mxGraphJs; -mxClipboard.cellsToString = (cells) => { +mxClipboard.cellsToString = (cells: ImxCell[]) => { const codec = new mxCodec(); const model = new mxGraphModel(); const parent = model.getChildAt(model.getRoot(), 0); @@ -36,8 +36,8 @@ export interface IClipboardContext { copyFunc(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; copyFuncForMenu(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; cutFunc(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; - pasteFunc(evt: ClipboardEvent, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX: number, mouseY: number): void; - pasteFuncForMenu(result: string, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX: number, mouseY: number): void; + pasteFunc(evt: ClipboardEvent, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX?: number, mouseY?: number): void; + pasteFuncForMenu(result: string, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX?: number, mouseY?: number): void; beforeUsingClipboard(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; afterUsingClipboard(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; } @@ -192,8 +192,6 @@ export const ClipboardContext = React.createContext({ copyFunc: (graph, copy, textInput) => { if (graph.isEnabled() && !graph.isSelectionEmpty()) { copyCells(graph, mxUtils.sortCells(graph.model.getTopmostCells(graph.getSelectionCells())), copy, textInput); - // tslint:disable-next-line: no-console - console.log(textInput.value); copy.dx = 0; copy.dy = 0; } @@ -201,15 +199,14 @@ export const ClipboardContext = React.createContext({ copyFuncForMenu: (graph, copy, textInput) => { if (graph.isEnabled() && !graph.isSelectionEmpty()) { copyCells(graph, mxUtils.sortCells(graph.model.getTopmostCells(graph.getSelectionCells())), copy, textInput); - // tslint:disable-next-line: no-console - console.log(textInput.value); copy.dx = 0; copy.dy = 0; } }, cutFunc: (graph, copy, textInput) => { if (graph.isEnabled() && !graph.isSelectionEmpty()) { - copyCells(graph, graph.removeCells(), copy, textInput); + const cells = graph.model.getTopmostCells(graph.getSelectionCells()); + copyCells(graph, graph.removeCells(cells), copy, textInput); copy.dx = -copy.gs; copy.dy = -copy.gs; } @@ -247,6 +244,7 @@ export const ClipboardContext = React.createContext({ textInput.select(); }, beforeUsingClipboard: (graph, copy, textInput) => { + // console.log("befor", graph.model.cells.ea1184e8.geometry , copy.restoreFocus, textInput); if (!copy.restoreFocus) { textInput.style.position = "absolute"; textInput.style.left = `${(graph.container.scrollLeft + 10)}px`; @@ -259,6 +257,7 @@ export const ClipboardContext = React.createContext({ } }, afterUsingClipboard: (graph, copy, textInput) => { + // console.log("after", copy.restoreFocus); if (copy.restoreFocus) { copy.restoreFocus = false; if (!graph.isEditing()) { graph.container.focus(); } diff --git a/src/context/MxGraphContext.ts b/src/context/MxGraphContext.ts index 7a1b72b..8979455 100644 --- a/src/context/MxGraphContext.ts +++ b/src/context/MxGraphContext.ts @@ -7,7 +7,7 @@ import { ICustomShape } from "../types/shapes"; export interface IMxGraphContext { graph?: IMxGraph; - action?: IMxActions; + actions?: IMxActions; customShape?: ICustomShape[]; customCommand?: ICustomCommand[]; setGraph(graph: IMxGraph): void; diff --git a/src/settings/port.ts b/src/settings/port.ts index 3e13c56..ceaf0dc 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -6,6 +6,7 @@ const { mxGraph, mxConstants, mxPerimeter, + mxGraphHandler, mxEdgeHandler, mxVertexHandler, mxRectangle, @@ -31,8 +32,8 @@ function setPortHandler(graph: IMxGraph): void { shape.isRounded = state.style[mxConstants.STYLE_ROUNDED]; const isPort = this.graph.isPort(state.cell); - shape.fill = isPort ? state.style[mxConstants.STYLE_FILLCOLOR] : state.style[mxConstants.STYLE_STROKECOLOR]; - shape.stroke = state.style[mxConstants.STYLE_STROKECOLOR]; + shape.fill = isPort ? state.style[mxConstants.STYLE_FILLCOLOR] : this.getSelectionColor(); + shape.stroke = this.getSelectionColor(); shape.fillOpacity = isPort ? 100 : 20; shape.strokeOpacity = 100; @@ -169,19 +170,23 @@ function setTooltips(graph: IMxGraph) { function setSelectionRecursively(graph: IMxGraph) { mxGraphSelectionModel.prototype.setCell = function (cell: ImxCell) { if (cell != null) { - const cells = [cell]; - if (cell.children) { - cell.children.forEach((port) => { - if (graph.isPort(port)) { - cells.push(port); - } - }) + if (cell.isEdge) { + this.setCells([cell]); + } else { + console.log(cell); + const cells = [cell, ...cell.children.filter(port => graph.isPort(port))]; + this.setCells(cells); } - this.setCells(cells); } }; } +function preventChildrenFromBeingRemoved(graph: IMxGraph) { + graph.graphHandler.shouldRemoveCellsFromParent = (parent, cells, evt) => { + return cells.length == 0 && !cells[0].geometry.relative && mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply(this, arguments); + }; +} + // tslint:disable-next-line: export-name export function initPort(graph: IMxGraph) { @@ -203,6 +208,8 @@ export function initPort(graph: IMxGraph) { return label; } + preventChildrenFromBeingRemoved(graph); + graph.isPort = (cell) => { const geo = graph.getCellGeometry(cell); return geo ? graph.getModel().isVertex(cell) && geo.relative : false; diff --git a/src/types/action.ts b/src/types/action.ts index 9197c46..f34ee7e 100644 --- a/src/types/action.ts +++ b/src/types/action.ts @@ -3,17 +3,16 @@ import { IMxGraph, IMxUndoManager } from "./mxGraph"; export interface IMxAction { label?: string; - shortcut?: string; - func(): void; + shortcuts?: string[]; + func(trigger?: object): void; } export interface IMxActions { - copy?: IMxAction; - cut?: IMxAction; - paste: { - getFunc(destX?: number, destY?: number): () => void; - }; - redo?: IMxAction; + copy: IMxAction; + cut: IMxAction; + pasteHere: IMxAction; + paste: IMxAction; + redo: IMxAction; undo: IMxAction; zoomIn: IMxAction; zoomOut: IMxAction; @@ -21,11 +20,13 @@ export interface IMxActions { fit: IMxAction; toFront: IMxAction; toBack: IMxAction; + actual: IMxAction; } export const actionType = [ "copy", "cut", + "pasteHere", "paste", "redo", "undo", @@ -35,10 +36,10 @@ export const actionType = [ "fit", "toFront", "toBack", + "actual", ]; - // tslint:disable-next-line: max-func-body-length -export function initAction(graph: IMxGraph, clipboard: IClipboardContext, undoManager: IMxUndoManager): IMxActions { +export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoManager: IMxUndoManager): IMxActions { return { copy: { func: () => { @@ -57,6 +58,7 @@ export function initAction(graph: IMxGraph, clipboard: IClipboardContext, undoMa console.log("Error! could not copy text", err); }); }, + shortcuts: ["ctrl + c"] }, cut: { func: () => { @@ -75,27 +77,47 @@ export function initAction(graph: IMxGraph, clipboard: IClipboardContext, undoMa console.log("Error! could not copy text", err); }); }, + shortcuts: ["ctrl + x"] + }, + pasteHere: { + func: (trigger: {x: number; y: number}) => { + navigator.clipboard.readText() + .then( + // tslint:disable-next-line: promise-function-async + (result) => { + // tslint:disable-next-line: no-console + console.log("Successfully retrieved text from clipboard", result); + clipboard.textInput.focus(); // no listener + // tslint:disable-next-line: deprecation + clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput, trigger.x, trigger.y); + return Promise.resolve(result); + } + ) + .catch( + (err) => { + throw new Error("Error! read text from clipboard"); + }); + }, + shortcuts: ["ctrl + v"] }, paste: { - getFunc(destX?: number, destY?: number): () => void { - return () => { - navigator.clipboard.readText() - .then( - // tslint:disable-next-line: promise-function-async - (result) => { - // tslint:disable-next-line: no-console - console.log("Successfully retrieved text from clipboard", result); - clipboard.textInput.focus(); // no listener - // tslint:disable-next-line: deprecation - clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput, destX, destY); - return Promise.resolve(result); - } - ) - .catch( - (err) => { - throw new Error("Error! read text from clipboard"); - }); - }; + func: () => { + navigator.clipboard.readText() + .then( + // tslint:disable-next-line: promise-function-async + (result) => { + // tslint:disable-next-line: no-console + console.log("Successfully retrieved text from clipboard", result); + clipboard.textInput.focus(); // no listener + // tslint:disable-next-line: deprecation + clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput); + return Promise.resolve(result); + } + ) + .catch( + (err) => { + throw new Error("Error! read text from clipboard"); + }); }, }, undo: { @@ -110,11 +132,13 @@ export function initAction(graph: IMxGraph, clipboard: IClipboardContext, undoMa }, zoomIn: { func: () => { + console.log(graph.container.clientWidth, graph.container.clientHeight); graph.zoomIn(); }, }, zoomOut: { func: () => { + graph.zoomOut(); }, }, @@ -128,6 +152,11 @@ export function initAction(graph: IMxGraph, clipboard: IClipboardContext, undoMa graph.fit(); } }, + actual: { + func: () => { + graph.actual(); + } + }, toFront: { func: () => { graph.orderCells(false); diff --git a/src/types/mxGraph.ts b/src/types/mxGraph.ts index 9ce6607..4be4fd2 100644 --- a/src/types/mxGraph.ts +++ b/src/types/mxGraph.ts @@ -183,6 +183,13 @@ export interface IMxMouseEvent { getState(): IMxState; } +interface IKeyHandler { + bindKey(keycode: number, evt: KeyboardEvent): void; + bindShiftKey(keycode: number, evt: KeyboardEvent): void; + bindControlKey(keycode: number, evt: KeyboardEvent): void; + bindControlShiftKey(keycode: number, evt: KeyboardEvent): void; +} + export interface IMxGraph { popupMenuHandler: { autoExpand: boolean; @@ -207,6 +214,7 @@ export interface IMxGraph { extendParents: boolean; defaultEdgeStyle: object; currentEdgeStyle: object; + keyHandler: IKeyHandler; addMouseListener(listener: { currentState: null | IMxState; mouseDown(sender: IMxGraph, me: IMxMouseEvent): void; @@ -240,6 +248,9 @@ export interface IMxGraph { selectCell(isNext: boolean, isParent?: boolean, isChild?: boolean): void; // selectAll(parent: ImxCell, descendants: ImxCell[]): void; // select all children of the given parent cell selectCells(vertices: ImxCell[], edges: ImxCell[], parent: ImxCell): void; + selectPreviousCell(): void; + selectParentCell(): void; + selectChildCell(): void; setHtmlLabels(bl: boolean): void; stopEditing(bl: boolean): void; isEnabled(): boolean; @@ -258,5 +269,6 @@ export interface IMxGraph { zoomIn(): void; zoomOut(): void; fit(): void; + actual(): void; orderCells(isToBack: boolean): void; } From 954b9fc88853ee12911deacb1fc645bc7f8d6577 Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Fri, 23 Aug 2019 19:56:07 +0800 Subject: [PATCH 02/12] modify port --- src/components/MxGraph.tsx | 3 ++- src/settings/port.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index a0eeb09..a4f0d6b 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -133,7 +133,6 @@ export class MxGraph extends React.PureComponent<{}, IState> { } - public componentWillMount(): void { if (!mxClient.isBrowserSupported()) { mxUtils.error("Browser is not supported!", 200, false); @@ -254,6 +253,8 @@ export class MxGraph extends React.PureComponent<{}, IState> { portStyle += ";shape=ellipse;perimeter=none;"; portStyle += "opacity=50"; + // vital + // portStyle += `;deletable=0`; const port = graph.insertVertex(vertex, null, `p${index}`, point[0], point[1], portSize[0], portSize[1], portStyle, true); port.geometry.offset = new mxPoint(-(portSize[0] / 2), -(portSize[1] / 2)); // set offset port.setConnectable(true); diff --git a/src/settings/port.ts b/src/settings/port.ts index ceaf0dc..59ecd63 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -170,22 +170,23 @@ function setTooltips(graph: IMxGraph) { function setSelectionRecursively(graph: IMxGraph) { mxGraphSelectionModel.prototype.setCell = function (cell: ImxCell) { if (cell != null) { - if (cell.isEdge) { + if (graph.getModel().isEdge(cell)) { this.setCells([cell]); } else { - console.log(cell); const cells = [cell, ...cell.children.filter(port => graph.isPort(port))]; + console.log(cells); this.setCells(cells); } } }; } -function preventChildrenFromBeingRemoved(graph: IMxGraph) { - graph.graphHandler.shouldRemoveCellsFromParent = (parent, cells, evt) => { - return cells.length == 0 && !cells[0].geometry.relative && mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply(this, arguments); - }; -} +// function preventChildrenFromBeingRemoved(graph: IMxGraph) { +// // graph.graphHandler.shouldRemoveCellsFromParent = (parent, cells, evt) => { +// // const bl = (cells.length == 0 && !cells[0].geometry.relative && mxGraphHandler.prototype.shouldRemoveCellsFromParent.apply(this, arguments)); +// // console.log(bl); +// // }; +// } // tslint:disable-next-line: export-name export function initPort(graph: IMxGraph) { @@ -208,7 +209,6 @@ export function initPort(graph: IMxGraph) { return label; } - preventChildrenFromBeingRemoved(graph); graph.isPort = (cell) => { const geo = graph.getCellGeometry(cell); From aea09385abc1c0039f2b78ae9b6d9ba7fd19806c Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Mon, 26 Aug 2019 16:04:52 +0800 Subject: [PATCH 03/12] repair mxutil getscrollorigin --- demo/app.tsx | 4 +- demo/appStyle.ts | 11 +- demo/src/components/FlowItemPanel.tsx | 2 + demo/src/components/FlowToolbar.tsx | 7 +- src/components/Command.tsx | 1 - src/components/DetailPanel.tsx | 1 + src/components/Flow.tsx | 2 +- src/components/Item.tsx | 2 +- src/components/MxGraph.tsx | 33 ++-- src/context/ClipboardContext.ts | 7 +- src/settings/init.ts | 241 ++++++++++---------------- src/settings/port.ts | 25 ++- src/types/action.ts | 6 +- src/types/mxGraph.ts | 37 ++-- src/types/shapes.ts | 41 ++++- 15 files changed, 212 insertions(+), 208 deletions(-) diff --git a/demo/app.tsx b/demo/app.tsx index 92fcd42..eae373d 100644 --- a/demo/app.tsx +++ b/demo/app.tsx @@ -26,7 +26,7 @@ const data = { shape: "rounded", color: "#FFFFFF", label: "起止节点", - x: 55, + x: 355, y: 55, id: "ea1184e8", index: 0, @@ -36,7 +36,7 @@ const data = { shape: "rounded2", color: "#FFFFFF", label: "结束节点", - x: 55, + x: 355, y: 255, id: "481fbb1a", index: 2, diff --git a/demo/appStyle.ts b/demo/appStyle.ts index 7d748ff..197885f 100644 --- a/demo/appStyle.ts +++ b/demo/appStyle.ts @@ -58,6 +58,7 @@ export const itemPanelStyles = { export const flowContainerStyles = { root: { width: "66.67%", + height: "800px", borderStyle: "solid", borderWidth: "1px", borderColor: "#a0aeb2", @@ -85,6 +86,7 @@ export const detailPanelStyles = { borderBottom: "1px", borderBottomStyle: "solid", borderBottomColor: "grey", + backgroundColor: "grey", } }; @@ -127,7 +129,7 @@ export const classNames = mergeStyleSets({ name: { display: 'inline-block', overflow: 'hidden', - height: 24, + height: 40, cursor: 'default', padding: 8, boxSizing: 'border-box', @@ -139,5 +141,10 @@ export const classNames = mergeStyleSets({ }, button: { border: 'none', + }, + item: { + backgroundColor: "gray", + height: 22, + width: 80, } -}); \ No newline at end of file +}); diff --git a/demo/src/components/FlowItemPanel.tsx b/demo/src/components/FlowItemPanel.tsx index fae8142..31b3857 100644 --- a/demo/src/components/FlowItemPanel.tsx +++ b/demo/src/components/FlowItemPanel.tsx @@ -57,9 +57,11 @@ export class FlowItemPanel extends React.PureComponent { return (

+
{item.shape} +
); diff --git a/demo/src/components/FlowToolbar.tsx b/demo/src/components/FlowToolbar.tsx index 40b124c..fac16d4 100644 --- a/demo/src/components/FlowToolbar.tsx +++ b/demo/src/components/FlowToolbar.tsx @@ -6,6 +6,7 @@ const { Stack, IconButton, initializeIcons, + FontIcon, } = Fabric; import { @@ -27,12 +28,16 @@ export const FlowToolbar = () => { + + - + + + ); diff --git a/src/components/Command.tsx b/src/components/Command.tsx index a6f1972..0a471ad 100644 --- a/src/components/Command.tsx +++ b/src/components/Command.tsx @@ -12,7 +12,6 @@ import { MenuItemContext, } from "../context/MenuContext"; - export class Command extends React.PureComponent<{name: string; text?: string}> { constructor(props: {name: string; text?: string}) { super(props); diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index 22f579e..ddd4ba0 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -60,6 +60,7 @@ export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> { private readonly _setListener = (graph: IMxGraph) => { graph.getSelectionModel().addListener(mxEvent.CHANGE, (sender: any, evt: any) => { + console.log(graph.getSelectionCells()[0], graph.getDefaultParent()); this.setState({cells: graph.getSelectionCells()}); }); } diff --git a/src/components/Flow.tsx b/src/components/Flow.tsx index 72043c0..c3319a5 100644 --- a/src/components/Flow.tsx +++ b/src/components/Flow.tsx @@ -48,7 +48,7 @@ export class Flow extends React.PureComponent { readData(graph, this.props.data); } return ( -
+
); }} diff --git a/src/components/Item.tsx b/src/components/Item.tsx index 2737965..2eb73a9 100644 --- a/src/components/Item.tsx +++ b/src/components/Item.tsx @@ -44,7 +44,7 @@ export class Item extends React.PureComponent{ public render(): React.ReactNode { return ( -
+
{this.props.children} {(context: IMxGraphContext) => { const { graph, insertVertex } = context; diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index a4f0d6b..99a1dc8 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -14,13 +14,14 @@ import { IMxActions, initActions } from "../types/action"; import { customShortcutDictionary, ICustomCommand } from "../types/command"; import { ICanvasData, ICanvasEdge, ICanvasNode } from "../types/flow"; import { + IKeyHandler, ImxCell, IMxEventObject, IMxGraph, IMxState, IMxUndoManager, - IKeyHandler, } from "../types/mxGraph"; +import { initBackground } from "../settings/background"; import { ICustomShape, } from "../types/shapes"; const { @@ -80,7 +81,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { this.addUndoEvent(graph); this.addCopyEvent(graph); - this.setMouseEvent(graph); + // this.setMouseEvent(graph); this.registerNode(graph); this.setState({ @@ -111,12 +112,16 @@ export class MxGraph extends React.PureComponent<{}, IState> { this.mouseX = evt.offsetX; this.mouseY = evt.offsetY; })); - mxEvent.addListener(graph.container, "mouseenter", mxUtils.bind(this, (evt: MouseEvent) => { - graph.setEnabled(true); - })); - mxEvent.addListener(graph.container, "mouseleave", mxUtils.bind(this, (evt: MouseEvent) => { - graph.setEnabled(false); - })); + // mxEvent.addListener(graph.container, "mouseenter", mxUtils.bind(this, (evt: MouseEvent) => { + // console.log("enter"); + // graph.setEnabled(true); + // })); + // mxEvent.addListener(graph.container, "mouseleave", mxUtils.bind(this, (evt: MouseEvent) => { + // console.log("leave"); + // graph.setEnabled(false); + // })); + + // initBackground(graph); } this.keyHandler.bindControlKey(67, () => { @@ -193,14 +198,6 @@ export class MxGraph extends React.PureComponent<{}, IState> { return keyHandler; } - private readonly addCustomKeyEvent = (graph: IMxGraph, func: () => void, key: string): void => { - mxEvent.addListener(document, "keydown", (event: KeyboardEvent) => { - if (graph.isEnabled() && !graph.isMouseDown && !graph.isEditing() && event.key === key) { - func(); - } - }); - } - private readonly registerNode = (graph: IMxGraph): void => { this.customShape.forEach((shape) => { const style = graph.getStylesheet() @@ -221,7 +218,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { if (customShortcutDictionary.hasOwnProperty(command.name) && customShortcutDictionary[command.name] && config.enable) { // tslint:disable-next-line: no-unbound-method this.addAction(graph, this.actions, command.name, config.execute, config.shortcutCodes); - console.log(command); + // console.log(command); } }); } @@ -254,7 +251,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { portStyle += ";shape=ellipse;perimeter=none;"; portStyle += "opacity=50"; // vital - // portStyle += `;deletable=0`; + portStyle += `;deletable=0`; const port = graph.insertVertex(vertex, null, `p${index}`, point[0], point[1], portSize[0], portSize[1], portStyle, true); port.geometry.offset = new mxPoint(-(portSize[0] / 2), -(portSize[1] / 2)); // set offset port.setConnectable(true); diff --git a/src/context/ClipboardContext.ts b/src/context/ClipboardContext.ts index 34fe504..771021c 100644 --- a/src/context/ClipboardContext.ts +++ b/src/context/ClipboardContext.ts @@ -45,7 +45,7 @@ export interface IClipboardContext { const copyCells = (graph: IMxGraph, cells: ImxCell[], copy: ICopy, textInput: HTMLTextAreaElement) => { if (cells.length > 0) { const clones = graph.cloneCells(cells); - + console.log(cells); for (let i = 0; i < clones.length; i += 1) { const state = graph.view.getState(cells[i]); // tslint:disable-next-line: strict-type-predicates triple-equals @@ -60,6 +60,7 @@ const copyCells = (graph: IMxGraph, cells: ImxCell[], copy: ICopy, textInput: HT } } textInput.value = mxClipboard.cellsToString(clones); // mxCell => xml + console.log( textInput.value ); } textInput.select(); copy.lastPaste = textInput.value; @@ -161,6 +162,7 @@ const _pasteText = (graph: IMxGraph, text: string, copy: ICopy, mouseX?: number, if (xml.substring(0, 14) === "") { const cells = _importXml(graph, xml, copy, destX, destY); graph.setSelectionCells(cells); + console.log(cells); graph.scrollCellToVisible(graph.getSelectionCells()); } } @@ -197,7 +199,10 @@ export const ClipboardContext = React.createContext({ } }, copyFuncForMenu: (graph, copy, textInput) => { + console.log( graph.isEnabled(), graph.isSelectionEmpty() ); if (graph.isEnabled() && !graph.isSelectionEmpty()) { + console.log( graph.getSelectionCells() ); + copyCells(graph, mxUtils.sortCells(graph.model.getTopmostCells(graph.getSelectionCells())), copy, textInput); copy.dx = 0; copy.dy = 0; diff --git a/src/settings/init.ts b/src/settings/init.ts index a5bf7fd..4166bed 100644 --- a/src/settings/init.ts +++ b/src/settings/init.ts @@ -1,7 +1,9 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { ImxCell, IMxGraph, IMxMouseEvent } from "../types/mxGraph"; +import { ImxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; import { initPort } from "./port"; +import { initEdgeHandle } from "./edge"; +import { initBackground } from "./background"; // import { registerShape } from "./Shapes"; const { mxEvent, @@ -18,91 +20,6 @@ const { mxUtils, } = mxGraphJs; -// override to disallow resizing of edge -// tslint:disable-next-statement -function initEdgeHandle(): void { - // tslint:disable - mxEdgeHandler.prototype.isHandleVisible = (index) => { - return true; - } - - // tslint:disable-next-line: cyclomatic-complexity - mxEdgeHandler.prototype.init = function () { - this.graph = this.state.view.graph; - this.marker = this.createMarker(); - this.constraintHandler = new mxConstraintHandler(this.graph); - - // Clones the original points from the cell - // and makes sure at least one point exists - this.points = []; - - // Uses the absolute points of the state - // for the initial configuration and preview - this.abspoints = this.getSelectionPoints(this.state); - this.shape = this.createSelectionShape(this.abspoints); - this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? - mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG; - this.shape.init(this.graph.getView().getOverlayPane()); - this.shape.pointerEvents = false; - this.shape.setCursor(mxConstants.CURSOR_MOVABLE_EDGE); - mxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state); - - // Updates preferHtml - this.preferHtml = this.state.text != null && - this.state.text.node.parentNode == this.graph.container; - - if (!this.preferHtml) { - // Checks source terminal - const sourceState = this.state.getVisibleTerminalState(true); - - if (sourceState != null) { - this.preferHtml = sourceState.text != null && - sourceState.text.node.parentNode == this.graph.container; - } - - if (!this.preferHtml) { - // Checks target terminal - const targetState = this.state.getVisibleTerminalState(false); - - if (targetState != null) { - this.preferHtml = targetState.text != null && - targetState.text.node.parentNode == this.graph.container; - } - } - } - - // Adds highlight for parent group - if (this.parentHighlightEnabled) { - const parent = this.graph.model.getParent(this.state.cell); - - if (this.graph.model.isVertex(parent)) { - const pstate = this.graph.view.getState(parent); - - if (pstate != null) { - this.parentHighlight = this.createParentHighlightShape(pstate); - // VML dialect required here for event transparency in IE - this.parentHighlight.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; - this.parentHighlight.pointerEvents = false; - this.parentHighlight.rotation = Number(pstate.style[mxConstants.STYLE_ROTATION] || '0'); - this.parentHighlight.init(this.graph.getView().getOverlayPane()); - } - } - } - // [remove a piece of code about initializing this.bends from the original function] - - // Adds a rectangular handle for the label position - this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y); - this.labelShape = this.createLabelHandleShape(); - this.initBend(this.labelShape); - this.labelShape.setCursor(mxConstants.CURSOR_LABEL_HANDLE); - - this.customHandles = this.createCustomHandles(); - console.log(this.marker); - this.redraw(); - // tslint:enable - }; - -} function initStyleSheet(graph: IMxGraph): void { const edgeStyle = graph.getStylesheet() @@ -138,8 +55,8 @@ function initStyleSheet(graph: IMxGraph): void { // tslint:disable function initHighlightShape(graph: IMxGraph): void { // Shows connection points only if cell not selected - graph.connectionHandler.constraintHandler.isStateIgnored = function (state, source) { - return source && state.view.graph.isCellSelected(state.cell); + graph.connectionHandler.constraintHandler.isStateIgnored = (state: IMxState, isSource: boolean) => { + return isSource && state.view.graph.isCellSelected(state.cell); }; // override mxConstraintHandler.prototype.highlightColor = mxConstants.DEFAULT_VALID_COLOR mxConstraintHandler.prototype.highlightColor = "#29b6f6"; @@ -184,7 +101,7 @@ function initHighlightShape(graph: IMxGraph): void { graph.connectionHandler.createEdgeState = function (me: IMxMouseEvent) { var edge = graph.createEdge(null, null, null, null, null); - + console.log(edge); return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge)); }; // Overrides edge preview to use current edge shape and default style @@ -211,7 +128,7 @@ function initHighlightShape(graph: IMxGraph): void { function setLabelUnmovable(): void { // tslint:disable-next-line: no-function-expression - mxGraph.prototype.isLabelMovable = function(cell: ImxCell): boolean { + mxGraph.prototype.isLabelMovable = function (cell: ImxCell): boolean { return false; }; } @@ -222,73 +139,102 @@ function unableDanglingEdges(graph: IMxGraph): void { } function repairDragCoordinate(): void { - // tslint:disable - mxDragSource.prototype.dragOver = function (graph, evt) { - var offset = mxUtils.getOffset(graph.container); - // var origin = mxUtils.getScrollOrigin(graph.container); - var origin = { x: 0, y: 0 }; - var x = mxEvent.getClientX(evt) - offset.x + origin.x - graph.panDx; - var y = mxEvent.getClientY(evt) - offset.y + origin.y - graph.panDy; - - if (graph.autoScroll && (this.autoscroll == null || this.autoscroll)) { - graph.scrollPointToVisible(x, y, graph.autoExtend); + mxUtils.getScrollOrigin = (node) => { + var b = document.body; + var d = document.documentElement; + if (!node || node === b || node === d) { + return {x: 0, y: 0}; } - - // Highlights the drop target under the mouse - if (this.currentHighlight != null && graph.isDropEnabled()) { - this.currentDropTarget = this.getDropTarget(graph, x, y, evt); - var state = graph.getView().getState(this.currentDropTarget); - this.currentHighlight.highlight(state); + console.log(node); + //console.log(node.ownerDocument); + // var result = mxUtils.getDocumentScrollOrigin((node != null) ? node.ownerDocument : document); + // console.log(result); + if(node) { + // console.log(node.ownerDocument); } - - // Updates the location of the preview - if (this.previewElement != null) { - if (this.previewElement.parentNode == null) { - graph.container.appendChild(this.previewElement); - - this.previewElement.style.zIndex = '3'; - this.previewElement.style.position = 'absolute'; + const result = {x:0, y:0}; + while (node != null && node != b && node != d) { + if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop)) { + result.x += node.scrollLeft; + result.y += node.scrollTop; } - var gridEnabled = this.isGridEnabled() && graph.isGridEnabledEvent(evt); - var hideGuide = true; - - // Grid and guides - if (this.currentGuide != null && this.currentGuide.isEnabledForEvent(evt)) { - // LATER: HTML preview appears smaller than SVG preview - var w = parseInt(this.previewElement.style.width); - var h = parseInt(this.previewElement.style.height); - var bounds = new mxRectangle(0, 0, w, h); - var delta = new mxPoint(x, y); - delta = this.currentGuide.move(bounds, delta, gridEnabled); - hideGuide = false; - x = delta.x; - y = delta.y; - } - else if (gridEnabled) { - var scale = graph.view.scale; - var tr = graph.view.translate; - var off = graph.gridSize / 2; - x = (graph.snap(x / scale - tr.x - off) + tr.x) * scale; - y = (graph.snap(y / scale - tr.y - off) + tr.y) * scale; + node = node.parentNode; + } + return result; + //return result; + }, + + // tslint:disable + mxDragSource.prototype.dragOver = function (graph, evt) { + var offset = mxUtils.getOffset(graph.container); + + var origin = mxUtils.getScrollOrigin(graph.container); + console.log(origin); + // var origin = { x: 0, y: 0 }; + var x = mxEvent.getClientX(evt) - offset.x + origin.x - graph.panDx; + var y = mxEvent.getClientY(evt) - offset.y + origin.y - graph.panDy; + + // console.log(x,y ); + if (graph.autoScroll && (this.autoscroll == null || this.autoscroll)) { + graph.scrollPointToVisible(x, y, graph.autoExtend); } - if (this.currentGuide != null && hideGuide) { - this.currentGuide.hide(); + // Highlights the drop target under the mouse + if (this.currentHighlight != null && graph.isDropEnabled()) { + this.currentDropTarget = this.getDropTarget(graph, x, y, evt); + var state = graph.getView().getState(this.currentDropTarget); + this.currentHighlight.highlight(state); } - if (this.previewOffset != null) { - x += this.previewOffset.x; - y += this.previewOffset.y; - } + // Updates the location of the preview + if (this.previewElement != null) { + if (this.previewElement.parentNode == null) { + graph.container.appendChild(this.previewElement); - this.previewElement.style.left = Math.round(x) + 'px'; - this.previewElement.style.top = Math.round(y) + 'px'; - this.previewElement.style.visibility = 'visible'; - } + this.previewElement.style.zIndex = '3'; + this.previewElement.style.position = 'absolute'; + } - this.currentPoint = new mxPoint(x, y); - }; + var gridEnabled = this.isGridEnabled() && graph.isGridEnabledEvent(evt); + var hideGuide = true; + + // Grid and guides + if (this.currentGuide != null && this.currentGuide.isEnabledForEvent(evt)) { + // LATER: HTML preview appears smaller than SVG preview + var w = parseInt(this.previewElement.style.width); + var h = parseInt(this.previewElement.style.height); + var bounds = new mxRectangle(0, 0, w, h); + var delta = new mxPoint(x, y); + delta = this.currentGuide.move(bounds, delta, gridEnabled); + hideGuide = false; + x = delta.x; + y = delta.y; + } + else if (gridEnabled) { + var scale = graph.view.scale; + var tr = graph.view.translate; + var off = graph.gridSize / 2; + x = (graph.snap(x / scale - tr.x - off) + tr.x) * scale; + y = (graph.snap(y / scale - tr.y - off) + tr.y) * scale; + } + + if (this.currentGuide != null && hideGuide) { + this.currentGuide.hide(); + } + + if (this.previewOffset != null) { + x += this.previewOffset.x; + y += this.previewOffset.y; + } + + this.previewElement.style.left = Math.round(x) + 'px'; + this.previewElement.style.top = Math.round(y) + 'px'; + this.previewElement.style.visibility = 'visible'; + } + + this.currentPoint = new mxPoint(x, y); + }; // tslint:enable } @@ -310,4 +256,5 @@ export function init(graph: IMxGraph): void { graph.setHtmlLabels(true); initPort(graph); + } diff --git a/src/settings/port.ts b/src/settings/port.ts index 59ecd63..b26d7d8 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -27,7 +27,6 @@ function setPortHandler(graph: IMxGraph): void { mxVertexHandler.prototype.createSelectionShape = function (state) { const shape = this.graph.cellRenderer.createShape(state); shape.style = state.shape.style; - shape.isDashed = this.isSelectionDashed(); shape.isRounded = state.style[mxConstants.STYLE_ROUNDED]; const isPort = this.graph.isPort(state.cell); @@ -105,11 +104,11 @@ function setPortValidationStyle(graph: IMxGraph) { // and lead wrong intersection calculation in mxUtils.intersectsHotspot // but maybe it is useful somewhere else mxUtils.convertPoint = function(container: HTMLDivElement, x: number, y: number) { - // var origin = mxUtils.getScrollOrigin(container); + var origin = mxUtils.getScrollOrigin(container); var offset = mxUtils.getOffset(container); - // offset.x -= origin.x; - // offset.y -= origin.y; + offset.x -= origin.x; + offset.y -= origin.y; return new mxPoint(x - offset.x, y - offset.y); } @@ -168,16 +167,14 @@ function setTooltips(graph: IMxGraph) { } function setSelectionRecursively(graph: IMxGraph) { - mxGraphSelectionModel.prototype.setCell = function (cell: ImxCell) { - if (cell != null) { - if (graph.getModel().isEdge(cell)) { - this.setCells([cell]); - } else { - const cells = [cell, ...cell.children.filter(port => graph.isPort(port))]; - console.log(cells); - this.setCells(cells); - } - } + const selectModel = graph.getSelectionModel(); + const setCells = selectModel.setCells; + selectModel.setCells = function (cells: ImxCell[]) { + setCells.call( selectModel, + cells.filter( cell => cell != null) + .map( cell => cell.getChildCount() ? [cell, ...cell.children.filter(port => graph.isPort(port))] : [cell] ) + .reduce((arr, cells) => arr.concat(cells) , []) + ); }; } diff --git a/src/types/action.ts b/src/types/action.ts index f34ee7e..7060ae7 100644 --- a/src/types/action.ts +++ b/src/types/action.ts @@ -132,13 +132,11 @@ export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoM }, zoomIn: { func: () => { - console.log(graph.container.clientWidth, graph.container.clientHeight); graph.zoomIn(); }, }, zoomOut: { - func: () => { - + func: () => { graph.zoomOut(); }, }, @@ -154,7 +152,7 @@ export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoM }, actual: { func: () => { - graph.actual(); + graph.zoomActual(); } }, toFront: { diff --git a/src/types/mxGraph.ts b/src/types/mxGraph.ts index 4be4fd2..cae96a0 100644 --- a/src/types/mxGraph.ts +++ b/src/types/mxGraph.ts @@ -1,3 +1,10 @@ +import { + IConfig, + IMxPoint, + IMxRectangle, + IMxShape, + IMxText, +} from "./shapes"; // tslint:disable-next-line: no-empty-interface export interface IEdge { @@ -29,6 +36,7 @@ export interface ImxCell { absolutePoints: IMxPoint[]; setConnectable(isConnectable: boolean): void; getStyle(): string; + getChildCount(): number; setStyle(style: string): void; removeFromTerminal(isSource: boolean): void; // removes the edge from its source or target terminal getTerminal(isSource: boolean): ImxCell; // for edges @@ -89,11 +97,6 @@ export interface IGraphModel { setValue(cell: ImxCell, value: string): void; } -interface IMxPoint { - x: number; - y: number; -} - interface IGeometry { x: number; y: number; @@ -142,6 +145,13 @@ export interface IMxState { interface IMxSelectionModel { cells: ImxCell[]; graph: IMxGraph; + setCell(cell: ImxCell): void; + setCells(cells: ImxCell[]): void; + addCell(cell: ImxCell): void; + addCells(cells: ImxCell[]): void; + removeCell(cell: ImxCell): void; + removeCells(cells: ImxCell[]): void; + selectRegion(rect: IMxRectangle, evt: any): void; } export interface IStylesheet { @@ -154,8 +164,6 @@ export interface IStylesheet { getCellStyle(name: string, defaultStyle?: IStylesheet): IStylesheet; } -import { IConfig, IMxRectangle, IMxShape, IMxText } from "./shapes"; - interface ICellStyle extends IConfig { shape: string; perimeter: string; @@ -183,11 +191,11 @@ export interface IMxMouseEvent { getState(): IMxState; } -interface IKeyHandler { - bindKey(keycode: number, evt: KeyboardEvent): void; - bindShiftKey(keycode: number, evt: KeyboardEvent): void; - bindControlKey(keycode: number, evt: KeyboardEvent): void; - bindControlShiftKey(keycode: number, evt: KeyboardEvent): void; +export interface IKeyHandler { + bindKey(keycode: number, func: () => void): void; + bindShiftKey(keycode: number, func: () => void): void; + bindControlKey(keycode: number, func: () => void): void; + bindControlShiftKey(keycode: number, func: () => void): void; } export interface IMxGraph { @@ -235,11 +243,13 @@ export interface IMxGraph { getSelectionCell(): ImxCell; getSelectionModel(): IMxSelectionModel; getTooltipForCell(cell: ImxCell): IMxToolTip; + getGraphBounds(): void; insertVertex(parent: ImxCell, id?: string | null, value?: string, x?: number, y?: number, width?: number, height?: number, style?: string, isRelative?: boolean): ImxCell; insertEdge(parent: ImxCell, id?: string | null, value?: string, source?: ImxCell, target?: ImxCell): ImxCell; importCells(cells: ImxCell[], x: number, y: number, target: ImxCell): ImxCell[] | null; scrollCellToVisible(cells: ImxCell[]): void; setSelectionCells(cells: ImxCell[]): void; + setSelectionCell(cells: ImxCell[]): void; setTooltips(bl: boolean): void; setCellsResizable(bl: boolean): void; setConnectable(bl: boolean): void; @@ -252,6 +262,7 @@ export interface IMxGraph { selectParentCell(): void; selectChildCell(): void; setHtmlLabels(bl: boolean): void; + setEnabled(bl: boolean): void; stopEditing(bl: boolean): void; isEnabled(): boolean; isEditing(): boolean; @@ -269,6 +280,6 @@ export interface IMxGraph { zoomIn(): void; zoomOut(): void; fit(): void; - actual(): void; + zoomActual(): void; orderCells(isToBack: boolean): void; } diff --git a/src/types/shapes.ts b/src/types/shapes.ts index 66989bc..9c3891b 100644 --- a/src/types/shapes.ts +++ b/src/types/shapes.ts @@ -1,4 +1,4 @@ -import { IStylesheet } from "./mxGraph"; +import { IMxState, IStylesheet } from "./mxGraph"; export interface IConfig { rounded?: 0 | 1; @@ -20,8 +20,43 @@ export interface IConfig { points?: number[][]; } -interface IShape { - style: string; +export interface IShape { + style: string; +} + +export interface IMxShape { + apply(state: IMxState): void; + redraw(): void; +} + +export interface IMxRectangleShape extends IMxShape { + style: IConfig; + boundingBox: IMxRectangle; + bounds: IMxRectangle; +} + +export interface IMxText extends IMxShape { + style: IConfig; + background: string; + color: string; + cursor: string; + dialect: string; + family: string; + fill: string; +} + +export interface IMxPoint { + x: number; + y: number; + getCenterX(): number; + getCenterY(): number; + getPoint(): IMxPoint; +} + +export interface IMxRectangle extends IMxPoint { + height: number; + width: number; + intersect(rect: IMxRectangle): void; } export interface IShapeMap { From bd88e83522062c95f30b3c2b36ea7ce5e30ea40d Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Tue, 27 Aug 2019 19:02:41 +0800 Subject: [PATCH 04/12] demo --- demo/app.tsx | 3 + demo/appStyle.ts | 5 +- demo/index.scss | 51 ++++++- demo/src/components/FlowDetailForm.tsx | 85 +++++++++++ demo/src/components/FlowDetailPanel.tsx | 10 +- src/components/Command.tsx | 4 - src/components/ContextMenu.tsx | 3 - src/components/DetailPanel.tsx | 1 - src/components/Flow.tsx | 1 + src/components/Minimap.tsx | 5 +- src/components/Panel.tsx | 15 +- src/components/WithPropsApi.tsx | 195 ++++++++++++++++++------ src/index.ts | 1 + src/settings/edge.ts | 163 ++++++++++++++++++++ src/settings/guide.ts | 32 ++++ src/settings/init.ts | 16 +- src/settings/port.ts | 6 +- src/types/mxGraph.ts | 2 + src/types/propsAPI.ts | 32 ++++ src/types/shapes.ts | 2 + 20 files changed, 541 insertions(+), 91 deletions(-) create mode 100644 demo/src/components/FlowDetailForm.tsx create mode 100644 src/settings/edge.ts create mode 100644 src/settings/guide.ts create mode 100644 src/types/propsAPI.ts diff --git a/demo/app.tsx b/demo/app.tsx index eae373d..b3e99eb 100644 --- a/demo/app.tsx +++ b/demo/app.tsx @@ -16,6 +16,7 @@ import { Minimap, MxGraph, RegisterNode, + Minimap2, } from "../src/index"; import "./index.scss"; @@ -146,8 +147,10 @@ class Demo extends React.PureComponent { fontColor: "grey", fontSize: 10, strokeWidth: 1, strokeColor: "grey", shadow: 1, arcSize: 50 }} extend="rectangle" /> + {/* */} +
); } diff --git a/demo/appStyle.ts b/demo/appStyle.ts index 197885f..1a05a18 100644 --- a/demo/appStyle.ts +++ b/demo/appStyle.ts @@ -64,6 +64,7 @@ export const flowContainerStyles = { borderColor: "#a0aeb2", marginRight: "-1px", marginBottom: "-1px", + background: "" } } @@ -86,7 +87,7 @@ export const detailPanelStyles = { borderBottom: "1px", borderBottomStyle: "solid", borderBottomColor: "grey", - backgroundColor: "grey", + // backgroundColor: "grey", } }; @@ -120,7 +121,7 @@ export const headerAndFooterStyles: IRawStyle = { export const windowContainerStyles: IRawStyle = { minHeigh: 800, minWeight: 800, - Height: 1800, + Height: 1000, } export const classNames = mergeStyleSets({ diff --git a/demo/index.scss b/demo/index.scss index a56726b..833221f 100644 --- a/demo/index.scss +++ b/demo/index.scss @@ -56,4 +56,53 @@ body div.minimap-container { border-left: solid 1px #6F6F6F; border-right: solid 1px #6F6F6F; border-bottom: solid 1px #6F6F6F; -} \ No newline at end of file +} + +.slider { + position: fixed; + bottom: 10px; + left: 100px; + //width: 15%; + min-width: 220px; + max-width: 260px; + //border: solid 1px #000; + box-shadow: 0 2px 13px rgba(0,0,0,0.3); + cursor: grab; + opacity: 1; + // transition: opacity 800ms ease-in-out 200ms; + z-index: 999; + + &:hover { + opacity: 1; + transition-delay: 0ms; + } +} + +.slider__size { + position: relative; + z-index: 3; +} + +.slider__controller { +// outline: solid 3px black; + width: 100%; + padding-top: 100%; + position: absolute; + top: 0; + left: 0; + transform-origin: 0 0; + margin: -3px; + border-radius: 10px; + border: solid 3px black; +} + +.slider__content { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: -1; + transform-origin: 0 0; +} + diff --git a/demo/src/components/FlowDetailForm.tsx b/demo/src/components/FlowDetailForm.tsx new file mode 100644 index 0000000..f6ea964 --- /dev/null +++ b/demo/src/components/FlowDetailForm.tsx @@ -0,0 +1,85 @@ +import * as React from "react"; +import { withPropsApi } from "../../../src/index"; +import { ICanvasData } from "../../../src/types/flow"; +import { IPropsAPI } from "../../../src/types/propsAPI"; + +interface IProps { + propsAPI: IPropsAPI; +} + +import * as Fabric from "office-ui-fabric-react"; +import { StackItem } from "office-ui-fabric-react"; +import { ImxCell } from "../../../src/types/mxGraph"; + +const { + TextField, + Stack, +} = Fabric; + +export class DetailForm extends React.PureComponent { + private _isEditing: boolean; + get cell(): ImxCell { + const { propsAPI } = this.props; + return propsAPI.getSelected()[0]; + } + + constructor(props: IProps) { + super(props); + this.state = { + value: "...", + }; + this._isEditing = false; + } + public render(): React.ReactNode { + return ( + + + + + + ); + } + private readonly _onChange = (event) => { + this.setState({ value: event.target.value }); + } + + private readonly _getInputValue = (): string => { + const value = this._isEditing ? this.state.value : this._getCellValue(); + return value === null ? "" : value; + } + + private readonly stopEditing = () => { + const { update, } = this.props.propsAPI; + const cell = this.cell; + if (!cell) { + throw new Error("no cell to get value"); + } + update(cell, {label: this.state.value}); + this._isEditing = false; + } + private readonly _getCellValue = () => { + const { getCellModel, } = this.props.propsAPI; + const cell = this.cell; + // const model = graph.getModel(); + if (!cell) { + throw new Error("no cell to get value"); + } + const model = getCellModel(cell); + + return model.label; + } + + private readonly startEditing = () => { + const cell = this.cell; + if (!cell) { + throw new Error("no cells to get value"); + } + + const value = this._getCellValue(); + this.setState({ value, }); + + this._isEditing = true; + } +} + +export const FlowDetailForm = withPropsApi(DetailForm); diff --git a/demo/src/components/FlowDetailPanel.tsx b/demo/src/components/FlowDetailPanel.tsx index 9e73f3c..a24a855 100644 --- a/demo/src/components/FlowDetailPanel.tsx +++ b/demo/src/components/FlowDetailPanel.tsx @@ -7,17 +7,21 @@ import { TextEditor, } from "../../../src/index"; +import { + FlowDetailForm +} from "./FlowDetailForm"; + export const FlowDetailPanel = () => { return ( - + - + - + ); diff --git a/src/components/Command.tsx b/src/components/Command.tsx index 0a471ad..41c1334 100644 --- a/src/components/Command.tsx +++ b/src/components/Command.tsx @@ -3,10 +3,6 @@ import * as React from "react"; // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -const { - mxEvent, -} = mxGraphJs; - import { IMenuItemContext, MenuItemContext, diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 175b883..d317153 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -5,7 +5,6 @@ import * as React from "react"; const { mxEvent, mxUtils, - mxPopupMenuHandler, } = mxGraphJs; import { @@ -19,7 +18,6 @@ import { import { ClipboardContext, - IClipboardContext, } from "../context/ClipboardContext"; import { @@ -30,7 +28,6 @@ import { import { ImxCell, IMxGraph, - IMxMenu, } from "../types/mxGraph"; export class ContextMenu extends React.PureComponent { diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index ddd4ba0..1bc5778 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -47,7 +47,6 @@ export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> {
{this.props.children} -

{name}

); diff --git a/src/components/Flow.tsx b/src/components/Flow.tsx index c3319a5..a33490b 100644 --- a/src/components/Flow.tsx +++ b/src/components/Flow.tsx @@ -47,6 +47,7 @@ export class Flow extends React.PureComponent { if (graph) { readData(graph, this.props.data); } + // const Background = require("../../images/grid.gif"); return (
); diff --git a/src/components/Minimap.tsx b/src/components/Minimap.tsx index 85877dd..acfbfc0 100644 --- a/src/components/Minimap.tsx +++ b/src/components/Minimap.tsx @@ -17,9 +17,8 @@ interface IMinimapProps { height?: string; } -// tslint:disable-next-line: no-empty-interface interface IOutline { - + labelsVisible: boolean; } export class Minimap extends React.PureComponent { @@ -28,7 +27,7 @@ export class Minimap extends React.PureComponent { constructor(props: IMinimapProps) { super(props); - + mxOutline.prototype.labelsVisible = true; } public render(): React.ReactNode { return ( diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index 7667c04..df1935f 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -14,19 +14,10 @@ class Panel extends React.PureComponent<{name: string}> { } = value; if (name && cells && name === this.props.name) { - if (name === "edge") { - // console.log(cells[0]); - } - if (name === "port") { - // console.log(cells[0].style); - } return ( - -
- {`${name} panel:`} - {this.props.children} -
-
+
+ {this.props.children} +
); } return null; diff --git a/src/components/WithPropsApi.tsx b/src/components/WithPropsApi.tsx index f35d3c1..08b8011 100644 --- a/src/components/WithPropsApi.tsx +++ b/src/components/WithPropsApi.tsx @@ -9,32 +9,15 @@ import { ICanvasNode, } from "../types/flow"; import { ImxCell, IMxGraph } from "../types/mxGraph"; - +import { IPropsAPI, IModel } from "../types/propsAPI"; const { mxConstants, } = mxGraphJs; -export interface IPropsAPI { - graph: IMxGraph; - executeCommand(command: string): void; - find(id: string): ImxCell; - getSelected(): ImxCell[]; - read(data: ICanvasData): void; - save(): object; - add(name: "node" | "edge", model): void; - update(cell: ImxCell, model): void; - remove(cell: ImxCell): void; -} - -// tslint:disable-next-line: max-func-body-length -export function withPropsApi(WrappedComponent): React.PureComponent { - return class extends React.PureComponent { +export const withPropsApi = (WrappedComponent: any) => + class MakeCounter extends React.PureComponent { - constructor(props: {}) { - super(props); - } - // tslint:disable-next-line: max-func-body-length - public render(): React.ReactNode { + public render(): JSX.Element { return ( // tslint:disable-next-line: max-func-body-length {(value: IMxGraphContext) => { @@ -67,31 +50,26 @@ export function withPropsApi(WrappedComponent): React.PureComponent { }, // tslint:disable-next-line: cyclomatic-complexity save: () => { - const model = graph.getModel(); - const data: ICanvasData = { nodes: [], edges: [] }; - // formate - for (const [id, cell] of Object.entries(model.cells)) { - if (model.isEdge(cell)) { - const cellData: ICanvasEdge = {}; - if (cell.source) { cellData.source = cell.source.id; } - if (cell.target) { cellData.target = cell.target.id; } - cellData.id = id; - data.edges.push(cellData); - } else if (model.isVertex(cell)) { - const cellData: ICanvasNode = {}; - if (cell.value) { cellData.label = cell.value; } - cellData.id = id; - if (cell.geometry) { - cellData.size = [cell.geometry.width, cell.geometry.height]; - } - const style = graph.getCellStyle(cell); - cellData.shape = style.shape; - data.nodes.push(cellData); - } else { - // do nothing - } - } - return data; + const tmp = model.cells.map((cell) => propsAPI.getCellModel(cell)); + return { nodes: tmp.filter((cell) => !cell.edge), edges: tmp.filter((cell) => cell.edge) }; + }, + getCellModel: (cell: ImxCell) => { + const geo = model.getGeometry(cell); + const style = graph.getCellStyle(cell); + + const cellData: IModel = { + id: cell.id, + label: cell.value, + size: [geo.width, geo.height], + shape: style.shape, + color: style.fillColor, + edge: model.isEdge(cell), + x: geo.x, + y: geo.y, + }; + if (cell.source) { cellData.source = cell.source.id; } + if (cell.target) { cellData.target = cell.target.id; } + return cellData; }, add: (name: string, model: ICanvasEdge | ICanvasNode) => { const parent = graph.getDefaultParent(); @@ -109,7 +87,7 @@ export function withPropsApi(WrappedComponent): React.PureComponent { } }, update: (cell: ImxCell, model: ICanvasEdge | ICanvasNode) => { - if (!cell || graph.isPort(cell) ) { + if (!cell || graph.isPort(cell)) { return; } const { x, y, size, label, color } = model; @@ -155,7 +133,128 @@ export function withPropsApi(WrappedComponent): React.PureComponent { ); } }; -} + + +// // tslint:disable-next-line: max-func-body-length +// export function withPropsApi(WrappedComponent): React.PureComponent { +// return class extends React.PureComponent { + +// constructor(props: {}) { +// super(props); +// } +// // tslint:disable-next-line: max-func-body-length +// public render(): React.ReactNode { +// return ( +// // tslint:disable-next-line: max-func-body-length +// {(value: IMxGraphContext) => { +// const { +// graph, +// actions, +// readData, +// insertVertex, +// insertEdge, +// } = value; +// if (graph && actions) { +// const model = graph.getModel(); +// const propsAPI: IPropsAPI = { +// graph, +// executeCommand: (command) => { +// if (!actions.hasOwnProperty(command)) { +// throw new Error("this command is not initialized in action"); +// } +// actions[command].func(); +// }, +// find: (id) => { +// return graph.getModel() +// .getCell(id); +// }, +// getSelected: () => { +// console.log("?"); +// return graph.getSelectionCells(); +// }, +// read: (data) => { +// readData(graph, data); +// }, +// // tslint:disable-next-line: cyclomatic-complexity +// save: () => { +// const tmp = model.cells.map((cell) => propsAPI.getCellModel(cell)); +// return { nodes: tmp.filter((cell) => cell.type === "0"), edges: tmp.filter((cell) => cell.type === "1") }; +// }, +// getCellModel: (cell: ImxCell) => { +// const cellData: IModel = {}; +// if (cell.source ) cellData.source = cell.source.id; +// if (cell.target ) cellData.target = cell.target.id; +// cellData.id = cell.id; +// cellData.label = cell.value; +// cellData.size = [cell.geometry.width, cell.geometry.height]; +// const style = graph.getCellStyle(cell); +// cellData.shape = style.shape; +// cellData.type = model.isEdge(cell) ? "0" : "1"; +// return cellData; +// }, +// add: (name: string, model: ICanvasEdge | ICanvasNode) => { +// const parent = graph.getDefaultParent(); +// // tslint:disable-next-line: prefer-switch +// if (name === "node") { +// insertVertex(parent, graph, model); +// } else if (name === "edge") { +// const source = graph.getModel() +// .getCell(model.source); +// const target = graph.getModel() +// .getCell(model.target); +// if (source && target) { +// insertEdge(parent, graph, model, source, target); +// } +// } +// }, +// update: (cell: ImxCell, model: ICanvasEdge | ICanvasNode) => { +// if (!cell || graph.isPort(cell)) { +// return; +// } +// const { x, y, size, label, color } = model; +// const bounds = { +// x: x ? x : cell.geometry.x, +// y: y ? y : cell.geometry.y, +// width: size ? size[0] : cell.geometry.width, +// height: size ? size[1] : cell.geometry.height, +// }; +// graph.model.beginUpdate(); +// try { +// // resize +// graph.resizeCell(cell, bounds); +// // label +// if (label) { +// graph +// .getModel() +// .setValue(cell, label); +// } +// // update style by model +// if (color) { +// graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, color, [cell]); +// } +// } finally { +// graph.model.endUpdate(); +// } +// }, +// remove: (cell: ImxCell) => { + +// if (cell) { +// graph.removeCells([cell]); +// } else { +// // +// } +// } +// }; +// return ; +// } else { +// return null; +// } +// }} +// +// ); +// } +// }; +// } interface IProps { propsAPI: IPropsAPI; diff --git a/src/index.ts b/src/index.ts index ebf5bb5..aab5b38 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ export * from "./components/Command"; export * from "./components/Toolbar"; export * from "./components/ToolCommand"; export * from "./components/Minimap"; +export * from "./components/Minimap2"; export * from "./components/Panel"; export * from "./components/DetailPanel"; export * from "./components/TextEditor"; diff --git a/src/settings/edge.ts b/src/settings/edge.ts new file mode 100644 index 0000000..d9f949d --- /dev/null +++ b/src/settings/edge.ts @@ -0,0 +1,163 @@ +// @ts-ignore +import * as mxGraphJs from "mxgraph-js"; +import { ImxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; +// import { registerShape } from "./Shapes"; +const { + mxEvent, + mxConstraintHandler, + mxGraph, + mxPoint, + mxEllipse, + mxConstants, + mxEdgeHandler, + mxConnectionHandler, + mxCellState, + mxDragSource, + mxRectangle, + mxUtils, +} = mxGraphJs; + +const setSelectionShape = (): void => { + mxEdgeHandler.prototype.createSelectionShape = function (points) { + const shape = new this.state.shape.constructor(); + shape.outline = false; + // shape.apply(this.state); + + // // shape.fill = this.getSelectionColor(); + // shape.fill = "black"; + // shape.stroke = "black"; + // shape.isDashed = this.isSelectionDashed(); + // // shape.stroke = this.getSelectionColor(); + // shape.isShadow = false; + return shape; + }; + + mxEdgeHandler.prototype.drawPreview = function () { + if (this.isLabel) { + var b = this.labelShape.bounds; + var bounds = new mxRectangle(Math.round(this.label.x - b.width / 2), + Math.round(this.label.y - b.height / 2), b.width, b.height); + this.labelShape.bounds = bounds; + this.labelShape.redraw(); + } + else if (this.shape != null) { + this.shape.apply(this.state); + this.shape.points = this.abspoints; + this.shape.scale = this.state.view.scale; + this.shape.isDashed = this.isSelectionDashed(); + this.shape.stroke = this.getSelectionColor(); + this.shape.fill = this.getSelectionColor(); + this.shape.strokewidth = this.getSelectionStrokeWidth() / this.shape.scale / this.shape.scale; + this.shape.arrowStrokewidth = this.getSelectionStrokeWidth(); + this.shape.arrowStroke = this.getSelectionColor(); + this.shape.isShadow = false; + console.log(this.shape); + this.shape.redraw(); + } + + if (this.parentHighlight != null) { + this.parentHighlight.redraw(); + } + }; +}; + +const setEdgeUnmovable = (graph: IMxGraph): void => { + graph.isCellMovable = function(cell) { + var state = graph.view.getState(cell); + var style = (state != null) ? state.style : graph.getCellStyle(cell); + if( graph.getModel().isEdge(cell) ) return false; + return graph.isCellsMovable() && !graph.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0; + }; +}; + +// override to disallow resizing of edge +// tslint:disable-next-statement +export function initEdgeHandle(graph: IMxGraph): void { + // tslint:disable + mxEdgeHandler.prototype.isHandleVisible = (index) => { + return true; + } + + setSelectionShape(); + setEdgeUnmovable(graph); + + // tslint:disable-next-line: cyclomatic-complexity + mxEdgeHandler.prototype.init = function () { + this.graph = this.state.view.graph; + this.marker = this.createMarker(); + this.constraintHandler = new mxConstraintHandler(this.graph); + + // Clones the original points from the cell + // and makes sure at least one point exists + this.points = []; + + // Uses the absolute points of the state + // for the initial configuration and preview + this.abspoints = this.getSelectionPoints(this.state); + this.shape = this.createSelectionShape(this.abspoints); + this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? + mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG; + this.shape.init(this.graph.getView().getOverlayPane()); + this.shape.pointerEvents = false; + if (this.graph.isCellMovable(this.state.cell)) { + this.shape.setCursor(mxConstants.CURSOR_MOVABLE_EDGE); + } + mxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state); + + // Updates preferHtml + this.preferHtml = this.state.text != null && + this.state.text.node.parentNode == this.graph.container; + + if (!this.preferHtml) { + // Checks source terminal + const sourceState = this.state.getVisibleTerminalState(true); + + if (sourceState != null) { + this.preferHtml = sourceState.text != null && + sourceState.text.node.parentNode == this.graph.container; + } + + if (!this.preferHtml) { + // Checks target terminal + const targetState = this.state.getVisibleTerminalState(false); + + if (targetState != null) { + this.preferHtml = targetState.text != null && + targetState.text.node.parentNode == this.graph.container; + } + } + } + + // Adds highlight for parent group + if (this.parentHighlightEnabled) { + const parent = this.graph.model.getParent(this.state.cell); + + if (this.graph.model.isVertex(parent)) { + const pstate = this.graph.view.getState(parent); + + if (pstate != null) { + this.parentHighlight = this.createParentHighlightShape(pstate); + // VML dialect required here for event transparency in IE + this.parentHighlight.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG; + this.parentHighlight.pointerEvents = false; + this.parentHighlight.rotation = Number(pstate.style[mxConstants.STYLE_ROTATION] || '0'); + this.parentHighlight.init(this.graph.getView().getOverlayPane()); + } + } + } + // [remove a piece of code about initializing this.bends from the original function] + + // Adds a rectangular handle for the label position + this.label = new mxPoint(this.state.absoluteOffset.x, this.state.absoluteOffset.y); + this.labelShape = this.createLabelHandleShape(); + this.initBend(this.labelShape); + this.labelShape.setCursor(mxConstants.CURSOR_LABEL_HANDLE); + + this.customHandles = this.createCustomHandles(); + console.log(this.marker); + this.redraw(); + // tslint:enable + }; + +} + diff --git a/src/settings/guide.ts b/src/settings/guide.ts new file mode 100644 index 0000000..e512628 --- /dev/null +++ b/src/settings/guide.ts @@ -0,0 +1,32 @@ +// @ts-ignore +import * as mxGraphJs from "mxgraph-js"; +import { IMxGraph } from '../types/mxGraph'; +const { + mxConstants, + mxEvent, + mxEdgeHandler, + mxGraphHandler, +} = mxGraphJs; + +// graph.moveCells(graph.getSelectionCells(), dx, dy); + +// tslint:disable-next-line: export-name +export const initGuides = (graph: IMxGraph) => { + mxGraphHandler.prototype.guidesEnabled = true; + // console.log(graph.graphHandler.guideEnabled); + // graph.graphHandler.guideEnabled = true; + // // graph.graphHandler.useGuidesForEvent = function (me) { + // // return !mxEvent.isAltDown(me.getEvent()); + // // }; + // console.log(graph.graphHandler.guideEnabled); + // // Defines the guides to be red (default) + mxConstants.GUIDE_COLOR = '#135995'; + + // // Defines the guides to be 1 pixel (default) + // mxConstants.GUIDE_STROKEWIDTH = 1; + + // // Enables snapping waypoints to terminals + // mxEdgeHandler.prototype.snapToTerminals = true; + + graph.gridSize = 10; +} diff --git a/src/settings/init.ts b/src/settings/init.ts index 4166bed..daf6034 100644 --- a/src/settings/init.ts +++ b/src/settings/init.ts @@ -145,13 +145,7 @@ function repairDragCoordinate(): void { if (!node || node === b || node === d) { return {x: 0, y: 0}; } - console.log(node); - //console.log(node.ownerDocument); - // var result = mxUtils.getDocumentScrollOrigin((node != null) ? node.ownerDocument : document); - // console.log(result); - if(node) { - // console.log(node.ownerDocument); - } + const result = {x:0, y:0}; while (node != null && node != b && node != d) { if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop)) { @@ -170,7 +164,7 @@ function repairDragCoordinate(): void { var offset = mxUtils.getOffset(graph.container); var origin = mxUtils.getScrollOrigin(graph.container); - console.log(origin); + // console.log(origin); // var origin = { x: 0, y: 0 }; var x = mxEvent.getClientX(evt) - offset.x + origin.x - graph.panDx; var y = mxEvent.getClientY(evt) - offset.y + origin.y - graph.panDy; @@ -237,7 +231,7 @@ function repairDragCoordinate(): void { }; // tslint:enable } - +import { initGuides } from "./guide"; export function init(graph: IMxGraph): void { mxGraph.prototype.tolerance = 8; @@ -249,12 +243,12 @@ export function init(graph: IMxGraph): void { graph.setConnectable(true); initStyleSheet(graph); - initEdgeHandle(); + initEdgeHandle(graph); initHighlightShape(graph); // html in-place editor graph.setHtmlLabels(true); initPort(graph); - + initGuides(graph); } diff --git a/src/settings/port.ts b/src/settings/port.ts index b26d7d8..f570a71 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -27,6 +27,7 @@ function setPortHandler(graph: IMxGraph): void { mxVertexHandler.prototype.createSelectionShape = function (state) { const shape = this.graph.cellRenderer.createShape(state); shape.style = state.shape.style; + shape.isDashed = this.isSelectionDashed(); shape.isRounded = state.style[mxConstants.STYLE_ROUNDED]; const isPort = this.graph.isPort(state.cell); @@ -100,9 +101,8 @@ function setPortValidationStyle(graph: IMxGraph) { } }; - // comment the code that calculates scroll offset since it causes wrong graphX graphY for mxMouseEvent - // and lead wrong intersection calculation in mxUtils.intersectsHotspot - // but maybe it is useful somewhere else + // the code calculates graphX and graphY of mxMouseEvent + // which involve intersection calculation in mxUtils.intersectsHotspot mxUtils.convertPoint = function(container: HTMLDivElement, x: number, y: number) { var origin = mxUtils.getScrollOrigin(container); var offset = mxUtils.getOffset(container); diff --git a/src/types/mxGraph.ts b/src/types/mxGraph.ts index cae96a0..936af00 100644 --- a/src/types/mxGraph.ts +++ b/src/types/mxGraph.ts @@ -87,6 +87,7 @@ export interface IGraphModel { getChildCount(root: ImxCell): number; getChildren(cell: ImxCell): ImxCell; getValue(cell: ImxCell): string | null; + getGeometry(cell: ImxCell): IGeometry; getTerminal(edge: ImxCell, isSource: boolean): ImxCell; // returns the source or target mxCell of the given edge depending on the value of the boolean parameter setTerminal(edge: ImxCell, terminal: ImxCell, isSourse: boolean): void; // to current transaction setTerminals(edge: ImxCell, source: ImxCell, target: ImxCell): void; // in a single transaction @@ -152,6 +153,7 @@ interface IMxSelectionModel { removeCell(cell: ImxCell): void; removeCells(cells: ImxCell[]): void; selectRegion(rect: IMxRectangle, evt: any): void; + addListener(name: string, func: () => void): void; } export interface IStylesheet { diff --git a/src/types/propsAPI.ts b/src/types/propsAPI.ts new file mode 100644 index 0000000..493ee41 --- /dev/null +++ b/src/types/propsAPI.ts @@ -0,0 +1,32 @@ +import { + ImxCell, + IMxGraph, +} from "./mxGraph"; + +import { ICanvasData } from "./flow"; + +export interface IModel { + x: number; + y: number; + size: [number, number]; + label: string; + color: string; + source: string; // cell id + target: string; // cell id + id: string; + shape: string; + edge: boolean; +} + +export interface IPropsAPI { + graph: IMxGraph; + executeCommand(command: string): void; + find(id: string): ImxCell; + getSelected(): ImxCell[]; + read(data: ICanvasData): void; + save(): object; + getCellModel(cell: ImxCell): IModel; + add(name: "node" | "edge", model: IModel): void; + update(cell: ImxCell, model: IModel): void; + remove(cell: ImxCell): void; +} diff --git a/src/types/shapes.ts b/src/types/shapes.ts index 9c3891b..c6e1615 100644 --- a/src/types/shapes.ts +++ b/src/types/shapes.ts @@ -54,6 +54,8 @@ export interface IMxPoint { } export interface IMxRectangle extends IMxPoint { + x: number; + y: number; height: number; width: number; intersect(rect: IMxRectangle): void; From c7a258a00262f632badcf903d17b9d1702e070a4 Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Wed, 28 Aug 2019 18:44:36 +0800 Subject: [PATCH 05/12] fix ts error --- demo/app.tsx | 8 +- demo/index.scss | 4 +- .../src/components/FlowCustomCommand.tsx | 16 +- demo/src/components/FlowDetailForm.tsx | 4 +- demo/src/index.ts | 3 +- src/components/ContextMenu.tsx | 35 +- src/components/DetailPanel.tsx | 24 +- src/components/Flow.tsx | 6 +- src/components/Item.tsx | 31 +- src/components/Minimap.tsx | 1 + src/components/MxGraph.tsx | 84 +- src/components/Panel.tsx | 1 - src/components/RegisterCommand.tsx | 1 - src/components/RegisterNode.tsx | 17 +- src/components/TextEditor.tsx | 116 -- src/components/WithNameProps.tsx | 5 +- src/components/WithPropsApi.tsx | 312 +---- src/context/ClipboardContext.ts | 56 +- src/context/MxGraphContext.ts | 22 +- src/context/PanelContext.ts | 6 +- src/index.ts | 6 +- src/settings/edge.ts | 29 +- src/settings/guide.ts | 24 +- src/settings/init.ts | 38 +- src/settings/port.ts | 52 +- src/types/action.ts | 84 +- src/types/clipboard.ts | 30 + src/types/flow.ts | 8 +- src/types/mxGraph.ts | 181 ++- src/types/propsAPI.ts | 59 +- src/types/shapes.ts | 7 +- stories/index.stories.tsx | 199 ++- test/__snapshots__/index.spec.tsx.snap | 1194 ++--------------- 33 files changed, 773 insertions(+), 1890 deletions(-) rename src/components/CustomCommand.tsx => demo/src/components/FlowCustomCommand.tsx (57%) delete mode 100644 src/components/TextEditor.tsx create mode 100644 src/types/clipboard.ts diff --git a/demo/app.tsx b/demo/app.tsx index b3e99eb..a02d6ba 100644 --- a/demo/app.tsx +++ b/demo/app.tsx @@ -4,19 +4,19 @@ import * as Fabric from "office-ui-fabric-react/lib"; import { FlowContextMenu, + FlowCustomCommand, FlowDetailPanel, FlowItemPanel, FlowToolbar, } from "./src/index"; import { - CustomCommand, Flow, - // ItemPanel, + // ItemPanel, Minimap, MxGraph, RegisterNode, - Minimap2, + // Minimap2, } from "../src/index"; import "./index.scss"; @@ -146,7 +146,7 @@ class Demo extends React.PureComponent { rounded: 1, fillColor: "white", points: [[0.5, 0], [0.33, 1], [0.67,1], [0, 0.5], [1, 0.5]], fontColor: "grey", fontSize: 10, strokeWidth: 1, strokeColor: "grey", shadow: 1, arcSize: 50 }} extend="rectangle" /> - + {/* */} diff --git a/demo/index.scss b/demo/index.scss index 833221f..0bc6064 100644 --- a/demo/index.scss +++ b/demo/index.scss @@ -49,8 +49,8 @@ table.mxPopupMenu tr { // } body div.minimap-container { - width: 200px; - height: 200px; + // width: 200px; + // height: 200px; margin: 5px; border-top: solid 1px #6F6F6F; border-left: solid 1px #6F6F6F; diff --git a/src/components/CustomCommand.tsx b/demo/src/components/FlowCustomCommand.tsx similarity index 57% rename from src/components/CustomCommand.tsx rename to demo/src/components/FlowCustomCommand.tsx index ccb74b0..7cece9a 100644 --- a/src/components/CustomCommand.tsx +++ b/demo/src/components/FlowCustomCommand.tsx @@ -1,27 +1,27 @@ import * as React from "react"; -import { RegisterCommand, withPropsApi } from "../index"; +import { RegisterCommand, withPropsApi } from "../../../src/index"; -import { IPropsAPI } from "../components/WithPropsApi"; +import { IPropsAPI } from "../../../src/types/propsAPI"; interface IProps { propsAPI: IPropsAPI; } -class ACommand extends React.PureComponent { +class CustomCommand extends React.PureComponent { public render(): React.ReactNode { - console.log("render"); + // console.log("render"); const { propsAPI } = this.props; - const { save, update, getSelected } = propsAPI; + const { update, getSelected } = propsAPI; const config = { enable(): boolean { return true; }, execute(): void { - const chart = save(); + // const chart = save(); const selectedNodes = getSelected(); - console.log(selectedNodes); + // console.log(selectedNodes); selectedNodes.map((node) => { update(node, {x : node.geometry.x + 2}); }); @@ -33,4 +33,4 @@ class ACommand extends React.PureComponent { } } -export const CustomCommand = withPropsApi(ACommand); +export const FlowCustomCommand = withPropsApi(CustomCommand); diff --git a/demo/src/components/FlowDetailForm.tsx b/demo/src/components/FlowDetailForm.tsx index f6ea964..c28c946 100644 --- a/demo/src/components/FlowDetailForm.tsx +++ b/demo/src/components/FlowDetailForm.tsx @@ -9,7 +9,7 @@ interface IProps { import * as Fabric from "office-ui-fabric-react"; import { StackItem } from "office-ui-fabric-react"; -import { ImxCell } from "../../../src/types/mxGraph"; +import { IMxCell } from "../../../src/types/mxGraph"; const { TextField, @@ -18,7 +18,7 @@ const { export class DetailForm extends React.PureComponent { private _isEditing: boolean; - get cell(): ImxCell { + get cell(): IMxCell { const { propsAPI } = this.props; return propsAPI.getSelected()[0]; } diff --git a/demo/src/index.ts b/demo/src/index.ts index 791bcaf..7574bc6 100644 --- a/demo/src/index.ts +++ b/demo/src/index.ts @@ -1,4 +1,5 @@ export * from "./components/FlowContextMenu"; export * from "./components/FlowDetailPanel"; export * from "./components/FlowItemPanel"; -export * from "./components/FlowToolbar"; \ No newline at end of file +export * from "./components/FlowToolbar"; +export * from "./components/FlowCustomCommand"; \ No newline at end of file diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index d317153..3b1203b 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -26,8 +26,7 @@ import { } from "../types/menu"; import { - ImxCell, - IMxGraph, + IMxCell, } from "../types/mxGraph"; export class ContextMenu extends React.PureComponent { @@ -44,8 +43,6 @@ export class ContextMenu extends React.PureComponent { } public render(): React.ReactNode { - // tslint:disable-next-line: deprecation - const { copy, textInput } = this.context; return ( @@ -67,23 +64,23 @@ export class ContextMenu extends React.PureComponent { // tslint:disable-next-line: cyclomatic-complexity currentMenu.forEach((item) => { const text = item.text ? item.text : "default"; - const type = item.menuItemType; + const command = item.menuItemType; // tslint:disable-next-line: prefer-switch - if (type === "separator") { + if (command === "separator") { menu.addSeparator(); } else { - if (!actions.hasOwnProperty(type)) { + if (!actions.hasOwnProperty(command)) { throw new Error("not be initialized in action"); } const menuItem = menu.addItem(text, null, () => { - actions[type].func({x: menu.triggerX, y: menu.triggerY}); + actions[command].func({x: menu.triggerX, y: menu.triggerY}); }); - const td = menuItem.firstChild.nextSibling.nextSibling; + const td = (menuItem.firstChild && menuItem.firstChild.nextSibling && menuItem.firstChild.nextSibling) ? menuItem.firstChild.nextSibling.nextSibling : null; const span = document.createElement("span"); span.style.color = "gray"; - const shortCutText = actions[type].shortcuts ? actions[type].shortcuts[0] : ""; + const shortCutText = actions[command].shortcuts ? actions[command].shortcuts[0] : ""; mxUtils.write(span, shortCutText); - td.appendChild(span); + if (td) { td.appendChild(span); } // tslint:disable-next-line: prefer-switch // if (item.menuItemType === "copy" || item.menuItemType === "cut") { // this.addListener(menuItem, graph, copy, textInput); @@ -102,22 +99,8 @@ export class ContextMenu extends React.PureComponent { ); } - private readonly addListener = (targetMenuItem: HTMLTableRowElement, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void => { - mxEvent.addListener(targetMenuItem, "pointerdown", (evt: PointerEvent) => { - // tslint:disable-next-line: deprecation - const source = mxEvent.getSource(evt); - if (graph.isEnabled() && !graph.isEditing() && source.nodeName !== "INPUT") { - // tslint:disable-next-line: deprecation - this.context.beforeUsingClipboard(graph, copy, textInput); - } - }); - mxEvent.addListener(targetMenuItem, "pointerup", (_evt: PointerEvent) => { - // tslint:disable-next-line: deprecation - this.context.afterUsingClipboard(graph, copy, textInput); - }); - } - private readonly _getMenuFromCell = (cell: ImxCell | null) => { + private readonly _getMenuFromCell = (cell: IMxCell | null) => { let name = "item"; if (cell === null) { name = "canvas"; diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index 1bc5778..f00cf1f 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -4,7 +4,6 @@ import * as React from "react"; import * as mxGraphJs from "mxgraph-js"; const { - mxGraphSelectionModel, mxEvent } = mxGraphJs; @@ -12,14 +11,13 @@ import { IMxGraphContext, MxGraphContext, } from "../context/MxGraphContext"; -import { ImxCell, IMxGraph, } from "../types/mxGraph"; +import { IMxCell, IMxGraph, } from "../types/mxGraph"; import { - IPanelContext, PanelContext, } from "../context/PanelContext"; -export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> { +export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> { public _first: boolean; constructor(props: {}) { super(props); @@ -44,7 +42,7 @@ export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> { } const name = this._getName(graph, this.state.cells); return ( - +
{this.props.children}
@@ -58,24 +56,26 @@ export class DetailPanel extends React.PureComponent<{}, {cells?: ImxCell[]}> { private readonly _setListener = (graph: IMxGraph) => { - graph.getSelectionModel().addListener(mxEvent.CHANGE, (sender: any, evt: any) => { - console.log(graph.getSelectionCells()[0], graph.getDefaultParent()); - this.setState({cells: graph.getSelectionCells()}); - }); + graph.getSelectionModel() + .addListener(mxEvent.CHANGE, (_sender, _evt) => { + // console.log(_sender, _evt); + // console.log(graph.getSelectionCells()[0], graph.getDefaultParent()); + this.setState({ cells: graph.getSelectionCells() }); + }); } - private readonly _getName = (graph: IMxGraph, cells?: ImxCell[]): string => { + private readonly _getName = (graph: IMxGraph, cells?: IMxCell[]): string => { if (!cells) { return "no selection"; } if (cells.length > 1) { if (cells.map((cell) => +!graph.isPort(cell)) - .reduce((acc, cur) => (acc + cur)) === 1) { + .reduce((acc, cur) => (acc + cur)) === 1) { return "vertex"; } return "multi"; - // tslint:disable-next-line: prefer-switch + // tslint:disable-next-line: prefer-switch } else if (cells.length === 1) { const cell = cells[0]; if (graph.isPort(cell)) { return "port"; } diff --git a/src/components/Flow.tsx b/src/components/Flow.tsx index a33490b..32b8bb1 100644 --- a/src/components/Flow.tsx +++ b/src/components/Flow.tsx @@ -15,7 +15,7 @@ import { IMxGraph } from "../types/mxGraph"; interface IFlowProps { data: ICanvasData; - shortcut: object; + shortcut?: object; } interface IFlowState { @@ -31,7 +31,9 @@ export class Flow extends React.PureComponent { private _setGraph?: (graph: IMxGraph) => void; constructor(props: IFlowProps) { super(props); - Object.assign(customShortcutDictionary, this.props.shortcut); + if (this.props.shortcut) { + Object.assign(customShortcutDictionary, this.props.shortcut); + } } public render(): React.ReactNode { diff --git a/src/components/Item.tsx b/src/components/Item.tsx index 2eb73a9..5165538 100644 --- a/src/components/Item.tsx +++ b/src/components/Item.tsx @@ -4,13 +4,7 @@ import * as React from "react"; import * as mxGraphJs from "mxgraph-js"; const { - mxCell, mxUtils, - mxGeometry, - mxConnectionConstraint, - mxPoint, - mxRectangleShape, - mxConstants, } = mxGraphJs; import { @@ -18,12 +12,15 @@ import { MxGraphContext, } from "../context/MxGraphContext"; -import { ICanvasNode } from "../types/flow"; import { - ImxCell, + IMxCell, IMxGraph, } from "../types/mxGraph"; +import { + ICanvasNode +} from "../types/flow"; + export interface IItemProps { shape: string; size?: string; @@ -34,7 +31,7 @@ export interface IItemProps { } export class Item extends React.PureComponent{ - public _insertVertex?: (parent: ImxCell, graph: IMxGraph, node: ICanvasNode) => ImxCell; + public _insertVertex?: (parent: IMxCell, graph: IMxGraph, node: ICanvasNode) => IMxCell; private readonly _containerRef = React.createRef(); private _graph?: IMxGraph; constructor(props: IItemProps) { @@ -72,22 +69,16 @@ export class Item extends React.PureComponent{ } public componentDidUpdate = () => { - console.log("item did update"); - } - - private readonly addVertex = (text: string, width: string, height: string, style: string): ImxCell => { - const vertex = new mxCell(text, new mxGeometry(0, 0, width, height), style); - vertex.setVertex(true); - return vertex; + // console.log("item did update"); } - private readonly insertNode = (graph: IMxGraph, _evt: PointerEvent, target: ImxCell, x: number, y: number): void => { + private readonly insertNode = (graph: IMxGraph, _evt: PointerEvent, target: IMxCell, x: number, y: number): void => { const label = this.props.model && this.props.model.label ? this.props.model.label : "none"; // tslint:disable-next-line: newline-per-chained-call const shape = this.props.shape; - const size = this.props.size ? (this.props.size.split("*") - // tslint:disable-next-line - .map((x) => parseInt(x))) : [100, 70]; + const tmp = this.props.size ? this.props.size.split("*") + .map((s) => parseInt(s, 10)) : [100, 70]; + const size: [number, number] = [tmp[0], tmp[1]]; const nodeData: ICanvasNode = { label, size, x, y, shape, }; if (!this._insertVertex) { diff --git a/src/components/Minimap.tsx b/src/components/Minimap.tsx index acfbfc0..bddbc55 100644 --- a/src/components/Minimap.tsx +++ b/src/components/Minimap.tsx @@ -52,5 +52,6 @@ export class Minimap extends React.PureComponent { throw new Error("empty minimap container"); } this.outline = new mxOutline(graph, this._containerRef.current); + if (this.outline) { this.outline.labelsVisible = true; } } } diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index 99a1dc8..40e7e9a 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -4,24 +4,25 @@ import * as React from "react"; import * as mxGraphJs from "mxgraph-js"; import { - ClipboardContext, IClipboardContext, + ClipboardContext, } from "../context/ClipboardContext"; import { MxGraphContext } from "../context/MxGraphContext"; import { init } from "../settings/init"; import { IMxActions, initActions } from "../types/action"; +import { IWindow } from "../types/clipboard"; import { customShortcutDictionary, ICustomCommand } from "../types/command"; import { ICanvasData, ICanvasEdge, ICanvasNode } from "../types/flow"; import { + IGraphModel, IKeyHandler, - ImxCell, + IMxCell, IMxEventObject, IMxGraph, IMxState, IMxUndoManager, } from "../types/mxGraph"; -import { initBackground } from "../settings/background"; import { ICustomShape, } from "../types/shapes"; const { @@ -37,9 +38,9 @@ const { mxRubberband, } = mxGraphJs; -window.mxGeometry = mxGeometry; -window.mxGraphModel = mxGraphModel; -window.mxPoint = mxPoint; +(window as IWindow).mxGeometry = mxGeometry; +(window as IWindow).mxGraphModel = mxGraphModel; +(window as IWindow).mxPoint = mxPoint; interface IState { graph?: IMxGraph; @@ -47,13 +48,13 @@ interface IState { export class MxGraph extends React.PureComponent<{}, IState> { public static contextType = ClipboardContext; - private undoManager: IMxUndoManager; + private undoManager?: IMxUndoManager; private mouseX: number; private mouseY: number; - private actions: IMxActions; + private actions?: IMxActions; private readonly customShape: ICustomShape[]; private readonly customCommand: ICustomCommand[]; - private keyHandler: IKeyHandler; + private keyHandler?: IKeyHandler; private _firstUpdate: boolean; constructor(props: {}) { @@ -73,15 +74,21 @@ export class MxGraph extends React.PureComponent<{}, IState> { return; } init(graph); - const rubberband = new mxRubberband(graph); + // tslint:disable-next-line: no-unused-expression + new mxRubberband(graph); this.undoManager = new mxUndoManager(); + if (!this.undoManager) { + throw new Error("undo manager is undefined"); + } // tslint:disable-next-line: deprecation this.actions = initActions(graph, this.context, this.undoManager); this.keyHandler = this.setKeyHandler(graph); - + if (!this.keyHandler) { + throw new Error("key handler is undefined"); + } this.addUndoEvent(graph); - this.addCopyEvent(graph); - // this.setMouseEvent(graph); + this.addCopyEvent(graph, this.keyHandler, this.actions); + this.setMouseEvent(graph); this.registerNode(graph); this.setState({ @@ -90,8 +97,8 @@ export class MxGraph extends React.PureComponent<{}, IState> { } public addUndoEvent = (graph: IMxGraph) => { - const listener = (_sender: IMxGraph, evt: IMxEventObject) => { - this.undoManager.undoableEditHappened(evt.getProperty("edit")); + const listener = (_sender: IGraphModel, evt: IMxEventObject) => { + (this.undoManager as IMxUndoManager).undoableEditHappened(evt.getProperty("edit")); }; graph.getModel() .addListener(mxEvent.UNDO, listener); @@ -99,7 +106,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { .addListener(mxEvent.UNDO, listener); } - public addCopyEvent = (graph: IMxGraph) => { + public addCopyEvent = (graph: IMxGraph, keyHandler: IKeyHandler, actions: IMxActions) => { // tslint:disable-next-line: deprecation const { copy, textInput } = this.context; copy.gs = graph.gridSize; @@ -112,28 +119,19 @@ export class MxGraph extends React.PureComponent<{}, IState> { this.mouseX = evt.offsetX; this.mouseY = evt.offsetY; })); - // mxEvent.addListener(graph.container, "mouseenter", mxUtils.bind(this, (evt: MouseEvent) => { - // console.log("enter"); - // graph.setEnabled(true); - // })); - // mxEvent.addListener(graph.container, "mouseleave", mxUtils.bind(this, (evt: MouseEvent) => { - // console.log("leave"); - // graph.setEnabled(false); - // })); - - // initBackground(graph); + } - this.keyHandler.bindControlKey(67, () => { - this.actions.copy.func(); + keyHandler.bindControlKey(67, () => { + actions.copy.func(); }); - this.keyHandler.bindControlKey(88, () => { - this.actions.cut.func(); + keyHandler.bindControlKey(88, () => { + actions.cut.func(); }); - this.keyHandler.bindControlKey(86, () => { - this.actions.pasteHere.func({ x: this.mouseX, y: this.mouseY }); + keyHandler.bindControlKey(86, () => { + actions.pasteHere.func({ x: this.mouseX, y: this.mouseY }); }); } @@ -145,7 +143,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { } public componentDidUpdate(): void { - if (this._firstUpdate && this.state.graph) { this.registerCommand(this.state.graph); this._firstUpdate = false; } + if (this._firstUpdate && this.state.graph) { this.registerCommand(this.state.graph, (this.actions as IMxActions)); this._firstUpdate = false; } } public render(): React.ReactNode { @@ -178,13 +176,13 @@ export class MxGraph extends React.PureComponent<{}, IState> { private readonly setKeyHandler = (graph: IMxGraph): IKeyHandler => { const keyHandler = new mxKeyHandler(graph); - keyHandler.bindControlKey(90, (evt: KeyboardEvent) => { - this.actions.undo.func(); + keyHandler.bindControlKey(90, (_evt: KeyboardEvent) => { + (this.actions as IMxActions).undo.func(); }); - keyHandler.bindKey(8, (evt: KeyboardEvent) => { - this.actions.deleteCell.func(); + keyHandler.bindKey(8, (_evt: KeyboardEvent) => { + (this.actions as IMxActions).deleteCell.func(); }); - keyHandler.bindKey(9, (evt: KeyboardEvent) => { + keyHandler.bindKey(9, (_evt: KeyboardEvent) => { if (graph.isEnabled()) { if (graph.isEditing()) { graph.stopEditing(false); @@ -212,18 +210,18 @@ export class MxGraph extends React.PureComponent<{}, IState> { }); } - private readonly registerCommand = (graph: IMxGraph): void => { + private readonly registerCommand = (graph: IMxGraph, action: IMxActions): void => { this.customCommand.forEach((command) => { const config = command.config; if (customShortcutDictionary.hasOwnProperty(command.name) && customShortcutDictionary[command.name] && config.enable) { // tslint:disable-next-line: no-unbound-method - this.addAction(graph, this.actions, command.name, config.execute, config.shortcutCodes); + this.addAction(graph, action, command.name, config.execute, config.shortcutCodes); // console.log(command); } }); } - private readonly insertVertex = (parent: ImxCell, graph: IMxGraph, node: ICanvasNode): ImxCell => { + private readonly insertVertex = (parent: IMxCell, graph: IMxGraph, node: ICanvasNode): IMxCell => { const model = graph.getModel(); @@ -264,7 +262,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { } - private readonly insertEdge = (parent: ImxCell, graph: IMxGraph, edge: ICanvasEdge, source: ImxCell, target: ImxCell): ImxCell => { + private readonly insertEdge = (parent: IMxCell, graph: IMxGraph, edge: ICanvasEdge, source: IMxCell, target: IMxCell): IMxCell => { return graph.insertEdge(parent, edge.id, "", source, target); } @@ -331,7 +329,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { } } - function drag(_evt, state: IMxState | null, isEnter: boolean): void { + function drag(_evt: PointerEvent, state: IMxState | null, isEnter: boolean): void { if (state) { updateStyle(state, isEnter); diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index df1935f..7ffafb2 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -2,7 +2,6 @@ import * as React from "react"; import { IPanelContext, PanelContext, - SpecialPanelContext, } from "../context/PanelContext"; class Panel extends React.PureComponent<{name: string}> { diff --git a/src/components/RegisterCommand.tsx b/src/components/RegisterCommand.tsx index de32e84..9904066 100644 --- a/src/components/RegisterCommand.tsx +++ b/src/components/RegisterCommand.tsx @@ -6,7 +6,6 @@ import { IMxGraphContext, MxGraphContext, } from "../context/MxGraphContext"; -import { IMxGraph } from "../types/mxGraph"; interface ICommandConfig { shortcutCodes: string[]; diff --git a/src/components/RegisterNode.tsx b/src/components/RegisterNode.tsx index e925f43..ac1b723 100644 --- a/src/components/RegisterNode.tsx +++ b/src/components/RegisterNode.tsx @@ -3,17 +3,16 @@ import * as React from "react"; // @ts-ignore import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext } from "../context/MxGraphContext"; -import { IStylesheet } from "../types/mxGraph"; const { mxCellRenderer, mxRectangleShape, mxEllipse, mxUtils, - mxConstants, - mxStylesheet, } = mxGraphJs; -import { IConfig } from "../types/shapes"; +import { + IConfig, +} from "../types/shapes"; type ExtendableShape = "rectangle" | "ellipse"; @@ -24,8 +23,10 @@ interface IRegisterNodeProps { } const builtInShape = { - rectangle: mxRectangleShape, - ellipse: mxEllipse, + // tslint:disable-next-line: ban-types + rectangle: (mxRectangleShape as Function), + // tslint:disable-next-line: ban-types + ellipse: (mxEllipse as Function), }; export class RegisterNode extends React.PureComponent { @@ -37,11 +38,11 @@ export class RegisterNode extends React.PureComponent { } const extendedShape = builtInShape[extend]; function registerShape(): void { + // @ts-ignore extendedShape.call(this); } mxUtils.extend(registerShape, extendedShape); - const a = mxCellRenderer.registerShape(this.props.name, registerShape); - // console.log(a, extendedShape, registerShape); + mxCellRenderer.registerShape(this.props.name, registerShape); } public render(): React.ReactNode { diff --git a/src/components/TextEditor.tsx b/src/components/TextEditor.tsx deleted file mode 100644 index 3387c78..0000000 --- a/src/components/TextEditor.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import * as React from "react"; - -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; - -const { - -} = mxGraphJs; - -import { - IMxGraphContext, - MxGraphContext, -} from "../context/MxGraphContext"; -import { - ISpecialPanelContext, - SpecialPanelContext, -} from "../context/PanelContext"; -import { ImxCell, IMxGraph } from "../types/mxGraph"; - -export class TextEditor extends React.PureComponent<{}, { value: string }> { - public _graph: IMxGraph; - private _cells: ImxCell[]; - private _first: boolean; - private _isEditing: boolean; - constructor(props: {}) { - super(props); - this.state = { - value: "...", - }; - this._first = true; - this._isEditing = false; - } - public render(): React.ReactNode { - return ( - {(panelValue: ISpecialPanelContext) => { - const { enabled, cells } = panelValue; - if (!enabled) { - return null; - } - this._cells = cells; - return ( - {(value: IMxGraphContext) => { - const { - graph, - } = value; - if (graph) { - if (this._first) { // initial after first render - this._graph = graph; - this._first = false; - } - return ( -
- -
- ); - } - }}
- ); - - }} -
- ); - } - private readonly _onChange = (event) => { - this.setState({ value: event.target.value }); - } - - private readonly _getInputValue = (): string => { - const value = this._isEditing ? this.state.value : this._getCellValue(); - return value === null ? "" : value; - } - - private readonly stopEditing = () => { - const graph = this._graph; - const cells = this._cells; - if (!cells) { - throw new Error("no cells to get value"); - } - for (const cell of cells) { - const model = graph.getModel(); - model.beginUpdate(); - try { - model.setValue(cell, this.state.value); - } finally { - model.endUpdate(); - } - } - this._isEditing = false; - } - private readonly _getCellValue = () => { - const cells = this._cells; - const model = this._graph.getModel(); - if (!cells) { - throw new Error("no cells to get value"); - } - if (cells.length) { - return model.getValue(cells[0]); - } else { - throw new Error("canvas has no value"); - } - } - - private readonly startEditing = () => { - const cells = this._cells; - if (!cells) { - throw new Error("no cells to get value"); - } - if (cells.length) { - const value = this._getCellValue(); - this.setState({ value, }); - } else { - throw new Error("canvas cannot edit text"); - } - this._isEditing = true; - } -} diff --git a/src/components/WithNameProps.tsx b/src/components/WithNameProps.tsx index d0fe914..b693f12 100644 --- a/src/components/WithNameProps.tsx +++ b/src/components/WithNameProps.tsx @@ -19,12 +19,13 @@ import * as React from "react"; // ) // } -export interface InjectedCounterProps { +export interface InjectedProps { name: string; } +// tslint:disable-next-line: no-any export const withNameProps = (Component: any, name: string) => - class MakeCounter extends React.PureComponent { + class WithNameProps extends React.PureComponent { public render(): JSX.Element { return ( diff --git a/src/components/WithPropsApi.tsx b/src/components/WithPropsApi.tsx index 08b8011..93df361 100644 --- a/src/components/WithPropsApi.tsx +++ b/src/components/WithPropsApi.tsx @@ -3,19 +3,24 @@ import * as React from "react"; // @ts-ignore import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext } from "../context/MxGraphContext"; +import { IEdge, IMxCell, } from "../types/mxGraph"; import { - ICanvasData, - ICanvasEdge, - ICanvasNode, -} from "../types/flow"; -import { ImxCell, IMxGraph } from "../types/mxGraph"; -import { IPropsAPI, IModel } from "../types/propsAPI"; + ICellModel, + IEdgeModel, + IModelEditor, + INodeModel, + IPropsAPI, + isEdgeModel, +} from "../types/propsAPI"; const { mxConstants, } = mxGraphJs; +// function isEdge(cell: ImxCell) + +// tslint:disable-next-line: export-name no-any export const withPropsApi = (WrappedComponent: any) => - class MakeCounter extends React.PureComponent { + class WithPropsApi extends React.PureComponent { public render(): JSX.Element { return ( @@ -28,8 +33,8 @@ export const withPropsApi = (WrappedComponent: any) => insertVertex, insertEdge, } = value; - if (graph && actions) { - const model = graph.getModel(); + if (graph && actions && insertEdge && insertVertex) { + const graphModel = graph.getModel(); const propsAPI: IPropsAPI = { graph, executeCommand: (command) => { @@ -48,45 +53,46 @@ export const withPropsApi = (WrappedComponent: any) => read: (data) => { readData(graph, data); }, - // tslint:disable-next-line: cyclomatic-complexity save: () => { - const tmp = model.cells.map((cell) => propsAPI.getCellModel(cell)); + const tmp = graphModel.cells.map((cell) => propsAPI.getCellModel(cell)); return { nodes: tmp.filter((cell) => !cell.edge), edges: tmp.filter((cell) => cell.edge) }; }, - getCellModel: (cell: ImxCell) => { - const geo = model.getGeometry(cell); + getCellModel: (cell: IMxCell) => { + const geo = graphModel.getGeometry(cell); const style = graph.getCellStyle(cell); - const cellData: IModel = { + // tslint:disable-next-line: no-any + const cellData: any = { id: cell.id, label: cell.value, size: [geo.width, geo.height], shape: style.shape, color: style.fillColor, - edge: model.isEdge(cell), - x: geo.x, - y: geo.y, + edge: graphModel.isEdge(cell), }; - if (cell.source) { cellData.source = cell.source.id; } - if (cell.target) { cellData.target = cell.target.id; } - return cellData; + if (graphModel.isEdge(cell)) { + cellData.source = (cell as IEdge).source.id; + cellData.target = (cell as IEdge).target.id; + return (cellData as IEdgeModel); + } else { + cellData.x = geo.x; + cellData.y = geo.y; + return (cellData as INodeModel); + } }, - add: (name: string, model: ICanvasEdge | ICanvasNode) => { + add: (model: ICellModel) => { const parent = graph.getDefaultParent(); - // tslint:disable-next-line: prefer-switch - if (name === "node") { + if (!(isEdgeModel(model))) { insertVertex(parent, graph, model); - } else if (name === "edge") { - const source = graph.getModel() - .getCell(model.source); - const target = graph.getModel() - .getCell(model.target); + } else { + const source = graphModel.getCell(model.source); + const target = graphModel.getCell(model.target); if (source && target) { insertEdge(parent, graph, model, source, target); } } }, - update: (cell: ImxCell, model: ICanvasEdge | ICanvasNode) => { + update: (cell: IMxCell, model: IModelEditor) => { if (!cell || graph.isPort(cell)) { return; } @@ -115,7 +121,7 @@ export const withPropsApi = (WrappedComponent: any) => graph.model.endUpdate(); } }, - remove: (cell: ImxCell) => { + remove: (cell: IMxCell) => { if (cell) { graph.removeCells([cell]); @@ -133,249 +139,3 @@ export const withPropsApi = (WrappedComponent: any) => ); } }; - - -// // tslint:disable-next-line: max-func-body-length -// export function withPropsApi(WrappedComponent): React.PureComponent { -// return class extends React.PureComponent { - -// constructor(props: {}) { -// super(props); -// } -// // tslint:disable-next-line: max-func-body-length -// public render(): React.ReactNode { -// return ( -// // tslint:disable-next-line: max-func-body-length -// {(value: IMxGraphContext) => { -// const { -// graph, -// actions, -// readData, -// insertVertex, -// insertEdge, -// } = value; -// if (graph && actions) { -// const model = graph.getModel(); -// const propsAPI: IPropsAPI = { -// graph, -// executeCommand: (command) => { -// if (!actions.hasOwnProperty(command)) { -// throw new Error("this command is not initialized in action"); -// } -// actions[command].func(); -// }, -// find: (id) => { -// return graph.getModel() -// .getCell(id); -// }, -// getSelected: () => { -// console.log("?"); -// return graph.getSelectionCells(); -// }, -// read: (data) => { -// readData(graph, data); -// }, -// // tslint:disable-next-line: cyclomatic-complexity -// save: () => { -// const tmp = model.cells.map((cell) => propsAPI.getCellModel(cell)); -// return { nodes: tmp.filter((cell) => cell.type === "0"), edges: tmp.filter((cell) => cell.type === "1") }; -// }, -// getCellModel: (cell: ImxCell) => { -// const cellData: IModel = {}; -// if (cell.source ) cellData.source = cell.source.id; -// if (cell.target ) cellData.target = cell.target.id; -// cellData.id = cell.id; -// cellData.label = cell.value; -// cellData.size = [cell.geometry.width, cell.geometry.height]; -// const style = graph.getCellStyle(cell); -// cellData.shape = style.shape; -// cellData.type = model.isEdge(cell) ? "0" : "1"; -// return cellData; -// }, -// add: (name: string, model: ICanvasEdge | ICanvasNode) => { -// const parent = graph.getDefaultParent(); -// // tslint:disable-next-line: prefer-switch -// if (name === "node") { -// insertVertex(parent, graph, model); -// } else if (name === "edge") { -// const source = graph.getModel() -// .getCell(model.source); -// const target = graph.getModel() -// .getCell(model.target); -// if (source && target) { -// insertEdge(parent, graph, model, source, target); -// } -// } -// }, -// update: (cell: ImxCell, model: ICanvasEdge | ICanvasNode) => { -// if (!cell || graph.isPort(cell)) { -// return; -// } -// const { x, y, size, label, color } = model; -// const bounds = { -// x: x ? x : cell.geometry.x, -// y: y ? y : cell.geometry.y, -// width: size ? size[0] : cell.geometry.width, -// height: size ? size[1] : cell.geometry.height, -// }; -// graph.model.beginUpdate(); -// try { -// // resize -// graph.resizeCell(cell, bounds); -// // label -// if (label) { -// graph -// .getModel() -// .setValue(cell, label); -// } -// // update style by model -// if (color) { -// graph.setCellStyles(mxConstants.STYLE_FILLCOLOR, color, [cell]); -// } -// } finally { -// graph.model.endUpdate(); -// } -// }, -// remove: (cell: ImxCell) => { - -// if (cell) { -// graph.removeCells([cell]); -// } else { -// // -// } -// } -// }; -// return ; -// } else { -// return null; -// } -// }} -// -// ); -// } -// }; -// } - -interface IProps { - propsAPI: IPropsAPI; - data: ICanvasData; -} - -// tslint:disable-next-line: max-classes-per-file -class TestComponent extends React.PureComponent { - constructor(props: IProps) { - super(props); - this.state = { - value: "", - cellV: "no find", - }; - } - - public render(): React.ReactNode { - return ( -
-

test with props api component

- - - - - - - -
-
- -
-
- -
- {this.state.cellV} -
-
- ); - } - - public handleChange = (event: React.SyntheticEvent) => { - this.setState({ value: event.target.value }); - } - - public handleSubmit = (event) => { - event.preventDefault(); - const cell = this.props.propsAPI.find(this.state.value); - const val = cell ? cell.value : "no found"; - this.setState({ cellV: val }); - } - - public getSelectionStyle = () => { - const cell = this.props.propsAPI.getSelected(); - const graph = this.props.propsAPI.graph; - // console.log(cell[0], graph.getCellStyle(cell[0])); - } - - public testUpdateCell = () => { - const cell = this.props.propsAPI.find("22"); - if (!cell) { - return; - } - this.props.propsAPI.update(cell, { - size: [30, 70], - x: cell.geometry.x - 10, - y: cell.geometry.y - 10, - label: "test", - color: "#CCCCCC", - }); - } - - public testRemoveCell = () => { - const cell = this.props.propsAPI.find("20"); - this.props.propsAPI.remove(cell); - } - - public testExeCopy = () => { - this.props.propsAPI.executeCommand("copy"); - } - - public testReadData = () => { - this.props.propsAPI.read(this.props.data); - } - - public testSaveData = () => { - // tslint:disable-next-line: no-console - console.log(this.props.propsAPI.save()); - } - - public testAddCell = () => { - this.props.propsAPI.add("node", - { - name: "node", - size: [100, 30], - shape: "rounded", - label: "add1", - x: 355, - y: 255, - id: "20", - }); - this.props.propsAPI.add("node", - { - name: "node", - size: [100, 30], - shape: "rounded", - label: "add2", - x: 355, - y: 355, - id: "22", - }); - this.props.propsAPI.add("edge", - { - source: "20", - target: "22", - id: "21", - }); - } -} - -// tslint:disable-next-line: export-name -export const PropsComponent = withPropsApi(TestComponent); diff --git a/src/context/ClipboardContext.ts b/src/context/ClipboardContext.ts index 771021c..0fbddd6 100644 --- a/src/context/ClipboardContext.ts +++ b/src/context/ClipboardContext.ts @@ -1,16 +1,19 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; import * as React from "react"; -import { ImxCell, IMxGraph } from "../types/mxGraph"; +import { IMxCell, IMxGraph } from "../types/mxGraph"; const { mxUtils, - mxEvent, mxClipboard, mxGraphModel, mxCodec, } = mxGraphJs; -mxClipboard.cellsToString = (cells: ImxCell[]) => { +import { + IClipboardEvent, +} from "../types/clipboard"; + +mxClipboard.cellsToString = (cells: IMxCell[]) => { const codec = new mxCodec(); const model = new mxGraphModel(); const parent = model.getChildAt(model.getRoot(), 0); @@ -36,16 +39,16 @@ export interface IClipboardContext { copyFunc(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; copyFuncForMenu(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; cutFunc(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; - pasteFunc(evt: ClipboardEvent, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX?: number, mouseY?: number): void; + pasteFunc(evt: IClipboardEvent, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX?: number, mouseY?: number): void; pasteFuncForMenu(result: string, graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement, mouseX?: number, mouseY?: number): void; beforeUsingClipboard(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; afterUsingClipboard(graph: IMxGraph, copy: ICopy, textInput: HTMLTextAreaElement): void; } -const copyCells = (graph: IMxGraph, cells: ImxCell[], copy: ICopy, textInput: HTMLTextAreaElement) => { +const copyCells = (graph: IMxGraph, cells: IMxCell[], copy: ICopy, textInput: HTMLTextAreaElement) => { if (cells.length > 0) { const clones = graph.cloneCells(cells); - console.log(cells); + // console.log(cells); for (let i = 0; i < clones.length; i += 1) { const state = graph.view.getState(cells[i]); // tslint:disable-next-line: strict-type-predicates triple-equals @@ -60,7 +63,7 @@ const copyCells = (graph: IMxGraph, cells: ImxCell[], copy: ICopy, textInput: HT } } textInput.value = mxClipboard.cellsToString(clones); // mxCell => xml - console.log( textInput.value ); + // console.log(textInput.value); } textInput.select(); copy.lastPaste = textInput.value; @@ -69,7 +72,7 @@ const copyCells = (graph: IMxGraph, cells: ImxCell[], copy: ICopy, textInput: HT const _importXml = (graph: IMxGraph, xml: XMLDocument, copy: ICopy, destX?: number, destY?: number) => { copy.dx = copy.dx ? copy.dx : 0; copy.dy = copy.dy ? copy.dy : 0; - let cells: ImxCell[] = []; + let cells: IMxCell[] = []; try { const doc = mxUtils.parseXml(xml); @@ -135,12 +138,12 @@ const _pasteText = (graph: IMxGraph, text: string, copy: ICopy, mouseX?: number, // console.log("text", text); let destX = mouseX ? mouseX / graph.view.scale - graph.view.translate.x : undefined; let destY = mouseY ? mouseY / graph.view.scale - graph.view.translate.y : undefined; - const x = graph.container.scrollLeft / graph.view.scale - graph.view.translate.x; - const y = graph.container.scrollTop / graph.view.scale - graph.view.translate.y; + // const x = graph.container.scrollLeft / graph.view.scale - graph.view.translate.x; + // const y = graph.container.scrollTop / graph.view.scale - graph.view.translate.y; if (xml.length > 0) { if (destX && destY) { - if (copy.lastPasteX < destX - copy.gs || copy.lastPasteX > destX + copy.gs || copy.lastPasteY < destY - copy.gs || copy.lastPasteY > destY + copy.gs) { + if (copy.lastPasteX < destX - copy.gs || copy.lastPasteX > destX + copy.gs || copy.lastPasteY < destY - copy.gs || copy.lastPasteY > destY + copy.gs) { copy.lastPasteX = destX; copy.lastPasteY = destY; } else { @@ -162,34 +165,36 @@ const _pasteText = (graph: IMxGraph, text: string, copy: ICopy, mouseX?: number, if (xml.substring(0, 14) === "") { const cells = _importXml(graph, xml, copy, destX, destY); graph.setSelectionCells(cells); - console.log(cells); + // console.log(cells); graph.scrollCellToVisible(graph.getSelectionCells()); } } }; -const _extractGraphModelFromEvent = (evt: ClipboardEvent) => { +const _extractGraphModelFromEvent = (evt: IClipboardEvent) => { let data = null; // tslint:disable-next-line: triple-equals strict-type-predicates if (evt != null) { const provider = (evt.dataTransfer) ? evt.dataTransfer : evt.clipboardData; + // tslint:disable-next-line: prefer-switch strict-type-predicates if (provider !== null) { - if (document.ducumentMode === 10 || document.documentMode === 11) { data = provider.getData("Text"); } - else { - data = (mxUtils.indexOf(provider.types, "text/html") >= 0) ? provider.getData("text/html") : null; - // tslint:disable-next-line: binary-expression-operand-order - if (mxUtils.indexOf(provider.types, "text/plain" && (data === null || data.length === 0))) { - data = provider.getData("text/plain"); - } + // tslint:disable-next-line: prefer-switch + // if (document.documentMode === 10 || document.documentMode === 11) { data = provider.getData("Text"); } + // else { + data = (mxUtils.indexOf(provider.types, "text/html") >= 0) ? provider.getData("text/html") : null; + // tslint:disable-next-line: binary-expression-operand-order + if (mxUtils.indexOf(provider.types, "text/plain" && (!data || data.length === 0))) { + data = provider.getData("text/plain"); } + // } } - } - return data; + + return data as string; }; export const ClipboardContext = React.createContext({ - copy: {gs: 0, dx: 0, dy: 0, lastPasteX: 0, lastPasteY: 0, lastPaste: null, restoreFocus: false}, + copy: { gs: 0, dx: 0, dy: 0, lastPasteX: 0, lastPasteY: 0, lastPaste: null, restoreFocus: false }, textInput: document.createElement("textarea"), copyFunc: (graph, copy, textInput) => { if (graph.isEnabled() && !graph.isSelectionEmpty()) { @@ -199,10 +204,7 @@ export const ClipboardContext = React.createContext({ } }, copyFuncForMenu: (graph, copy, textInput) => { - console.log( graph.isEnabled(), graph.isSelectionEmpty() ); if (graph.isEnabled() && !graph.isSelectionEmpty()) { - console.log( graph.getSelectionCells() ); - copyCells(graph, mxUtils.sortCells(graph.model.getTopmostCells(graph.getSelectionCells())), copy, textInput); copy.dx = 0; copy.dy = 0; @@ -220,7 +222,7 @@ export const ClipboardContext = React.createContext({ textInput.value = " "; if (graph.isEnabled()) { const xml = _extractGraphModelFromEvent(evt); - // tslint:disable-next-line: no-console + // tslint:disable-next-line: no-console strict-type-predicates if (xml !== null && xml.length > 0) { _pasteText(graph, xml, copy, mouseX, mouseY); } diff --git a/src/context/MxGraphContext.ts b/src/context/MxGraphContext.ts index 8979455..ad0b035 100644 --- a/src/context/MxGraphContext.ts +++ b/src/context/MxGraphContext.ts @@ -1,8 +1,12 @@ import * as React from "react"; import { IMxActions } from "../types/action"; import { ICustomCommand } from "../types/command"; -import { ICanvasData, ICanvasEdge, ICanvasNode } from "../types/flow"; -import { ImxCell, IMxGraph } from "../types/mxGraph"; +import { + ICanvasData, + ICanvasEdge, + ICanvasNode, +} from "../types/flow"; +import { IMxCell, IMxGraph } from "../types/mxGraph"; import { ICustomShape } from "../types/shapes"; export interface IMxGraphContext { @@ -12,21 +16,21 @@ export interface IMxGraphContext { customCommand?: ICustomCommand[]; setGraph(graph: IMxGraph): void; readData(graph: IMxGraph, data: ICanvasData): void; - insertEdge(parent: ImxCell, graph: IMxGraph, edge: ICanvasEdge, source: ImxCell, target: ImxCell): ImxCell; - insertVertex(parent: ImxCell, graph: IMxGraph, node: ICanvasNode): ImxCell; + insertEdge?(parent: IMxCell, graph: IMxGraph, edge: ICanvasEdge, source: IMxCell, target: IMxCell): IMxCell; + insertVertex?(parent: IMxCell, graph: IMxGraph, node: ICanvasNode): IMxCell; } export const MxGraphContext = React.createContext({ graph: undefined, // tslint:disable-next-line: no-empty setGraph: () => { }, - action: undefined, + actions: undefined, customShape: undefined, customCommand: undefined, // tslint:disable-next-line: no-empty readData: () => { }, - // tslint:disable-next-line: no-empty - insertEdge: () => null, - // tslint:disable-next-line: no-empty - insertVertex: () => null, + // // tslint:disable-next-line: no-empty + // insertEdge: () => null, + // // tslint:disable-next-line: no-empty + // insertVertex: () => null, }); diff --git a/src/context/PanelContext.ts b/src/context/PanelContext.ts index 328a55c..7635b5c 100644 --- a/src/context/PanelContext.ts +++ b/src/context/PanelContext.ts @@ -1,8 +1,8 @@ import * as React from "react"; -import { ImxCell } from "../types/mxGraph"; +import { IMxCell } from "../types/mxGraph"; export interface IPanelContext { - cells?: ImxCell[]; + cells?: IMxCell[]; name: string; } @@ -13,7 +13,7 @@ export const PanelContext = React.createContext({ export interface ISpecialPanelContext { enabled: boolean; - cells: ImxCell[]; + cells: IMxCell[]; } export const SpecialPanelContext = React.createContext({ diff --git a/src/index.ts b/src/index.ts index aab5b38..6d95de2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,11 +8,11 @@ export * from "./components/Command"; export * from "./components/Toolbar"; export * from "./components/ToolCommand"; export * from "./components/Minimap"; -export * from "./components/Minimap2"; +// export * from "./components/Minimap2"; export * from "./components/Panel"; export * from "./components/DetailPanel"; -export * from "./components/TextEditor"; +// export * from "./components/TextEditor"; export * from "./components/RegisterNode"; export * from "./components/WithPropsApi"; export * from "./components/RegisterCommand"; -export * from "./components/CustomCommand"; +// export * from "./components/CustomCommand"; diff --git a/src/settings/edge.ts b/src/settings/edge.ts index d9f949d..ef48e02 100644 --- a/src/settings/edge.ts +++ b/src/settings/edge.ts @@ -1,24 +1,20 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { ImxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; +import { IMxGraph } from "../types/mxGraph"; +import { IMxPoint, IMxShape } from "../types/shapes"; // import { registerShape } from "./Shapes"; const { mxEvent, mxConstraintHandler, - mxGraph, mxPoint, - mxEllipse, mxConstants, mxEdgeHandler, - mxConnectionHandler, - mxCellState, - mxDragSource, mxRectangle, - mxUtils, } = mxGraphJs; const setSelectionShape = (): void => { - mxEdgeHandler.prototype.createSelectionShape = function (points) { + mxEdgeHandler.prototype.createSelectionShape = function(_points: IMxPoint[]): IMxShape { + // tslint:disable-next-line: no-invalid-this const shape = new this.state.shape.constructor(); shape.outline = false; // shape.apply(this.state); @@ -32,7 +28,8 @@ const setSelectionShape = (): void => { return shape; }; - mxEdgeHandler.prototype.drawPreview = function () { + mxEdgeHandler.prototype.drawPreview = function(): void { + // tslint:disable if (this.isLabel) { var b = this.labelShape.bounds; var bounds = new mxRectangle(Math.round(this.label.x - b.width / 2), @@ -59,13 +56,16 @@ const setSelectionShape = (): void => { this.parentHighlight.redraw(); } }; + // tslint:enable }; const setEdgeUnmovable = (graph: IMxGraph): void => { - graph.isCellMovable = function(cell) { - var state = graph.view.getState(cell); - var style = (state != null) ? state.style : graph.getCellStyle(cell); - if( graph.getModel().isEdge(cell) ) return false; + graph.isCellMovable = (cell) => { + const state = graph.view.getState(cell); + const style = state ? state.style : graph.getCellStyle(cell); + if (graph.getModel() + .isEdge(cell)) { return false; } + // tslint:disable-next-line: triple-equals return graph.isCellsMovable() && !graph.isCellLocked(cell) && style[mxConstants.STYLE_MOVABLE] != 0; }; }; @@ -74,7 +74,7 @@ const setEdgeUnmovable = (graph: IMxGraph): void => { // tslint:disable-next-statement export function initEdgeHandle(graph: IMxGraph): void { // tslint:disable - mxEdgeHandler.prototype.isHandleVisible = (index) => { + mxEdgeHandler.prototype.isHandleVisible = (_index: number) => { return true; } @@ -160,4 +160,3 @@ export function initEdgeHandle(graph: IMxGraph): void { }; } - diff --git a/src/settings/guide.ts b/src/settings/guide.ts index e512628..517c314 100644 --- a/src/settings/guide.ts +++ b/src/settings/guide.ts @@ -1,11 +1,9 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { IMxGraph } from '../types/mxGraph'; +import { IMxGraph } from "../types/mxGraph"; const { - mxConstants, - mxEvent, - mxEdgeHandler, - mxGraphHandler, + mxConstants, + mxGraphHandler, } = mxGraphJs; // graph.moveCells(graph.getSelectionCells(), dx, dy); @@ -19,14 +17,14 @@ export const initGuides = (graph: IMxGraph) => { // // return !mxEvent.isAltDown(me.getEvent()); // // }; // console.log(graph.graphHandler.guideEnabled); - // // Defines the guides to be red (default) - mxConstants.GUIDE_COLOR = '#135995'; + // // Defines the guides to be red (default) + mxConstants.GUIDE_COLOR = "#135995"; - // // Defines the guides to be 1 pixel (default) - // mxConstants.GUIDE_STROKEWIDTH = 1; + // // Defines the guides to be 1 pixel (default) + // mxConstants.GUIDE_STROKEWIDTH = 1; - // // Enables snapping waypoints to terminals - // mxEdgeHandler.prototype.snapToTerminals = true; + // // Enables snapping waypoints to terminals + // mxEdgeHandler.prototype.snapToTerminals = true; - graph.gridSize = 10; -} + graph.gridSize = 10; +}; diff --git a/src/settings/init.ts b/src/settings/init.ts index daf6034..ef6e397 100644 --- a/src/settings/init.ts +++ b/src/settings/init.ts @@ -1,9 +1,8 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { ImxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; -import { initPort } from "./port"; +import { IMxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; import { initEdgeHandle } from "./edge"; -import { initBackground } from "./background"; +import { initPort } from "./port"; // import { registerShape } from "./Shapes"; const { mxEvent, @@ -12,7 +11,6 @@ const { mxPoint, mxEllipse, mxConstants, - mxEdgeHandler, mxConnectionHandler, mxCellState, mxDragSource, @@ -20,7 +18,6 @@ const { mxUtils, } = mxGraphJs; - function initStyleSheet(graph: IMxGraph): void { const edgeStyle = graph.getStylesheet() .getDefaultEdgeStyle(); @@ -30,7 +27,6 @@ function initStyleSheet(graph: IMxGraph): void { edgeStyle.strokeColor = "grey"; // "#1685a9"; edgeStyle.fontColor = "#000000"; edgeStyle.fontStyle = "0"; - edgeStyle.fontStyle = "0"; edgeStyle[mxConstants.STYLE_CURVED] = "1"; @@ -99,7 +95,7 @@ function initHighlightShape(graph: IMxGraph): void { // return null; // }; - graph.connectionHandler.createEdgeState = function (me: IMxMouseEvent) { + graph.connectionHandler.createEdgeState = function (_me: IMxMouseEvent) { var edge = graph.createEdge(null, null, null, null, null); console.log(edge); return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge)); @@ -128,7 +124,7 @@ function initHighlightShape(graph: IMxGraph): void { function setLabelUnmovable(): void { // tslint:disable-next-line: no-function-expression - mxGraph.prototype.isLabelMovable = function (cell: ImxCell): boolean { + mxGraph.prototype.isLabelMovable = function(_cell: IMxCell): boolean { return false; }; } @@ -139,28 +135,26 @@ function unableDanglingEdges(graph: IMxGraph): void { } function repairDragCoordinate(): void { - mxUtils.getScrollOrigin = (node) => { - var b = document.body; - var d = document.documentElement; + mxUtils.getScrollOrigin = (node: HTMLElement) => { + const b = document.body; + const d = document.documentElement; if (!node || node === b || node === d) { - return {x: 0, y: 0}; + return { x: 0, y: 0 }; } - const result = {x:0, y:0}; - while (node != null && node != b && node != d) { - if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop)) { - result.x += node.scrollLeft; - result.y += node.scrollTop; - } - - node = node.parentNode; + const result = { x: 0, y: 0 }; + // while (node !== null && node !== b && node !== d) { + if (!isNaN(node.scrollLeft) && !isNaN(node.scrollTop)) { + result.x += node.scrollLeft; + result.y += node.scrollTop; } + // node = node.parentNode; + // } return result; - //return result; }, // tslint:disable - mxDragSource.prototype.dragOver = function (graph, evt) { + mxDragSource.prototype.dragOver = function (graph: IMxGraph, evt: PointerEvent) { var offset = mxUtils.getOffset(graph.container); var origin = mxUtils.getScrollOrigin(graph.container); diff --git a/src/settings/port.ts b/src/settings/port.ts index f570a71..be3e144 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -1,12 +1,10 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { ImxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; +import { IMxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; const { mxGraph, mxConstants, - mxPerimeter, - mxGraphHandler, mxEdgeHandler, mxVertexHandler, mxRectangle, @@ -14,7 +12,6 @@ const { mxCellMarker, mxCellHighlight, mxGraphView, - mxGraphSelectionModel, mxClient, mxUtils, mxPoint, @@ -22,9 +19,9 @@ const { // tslint:disable -function setPortHandler(graph: IMxGraph): void { +function setPortHandler(_graph: IMxGraph): void { - mxVertexHandler.prototype.createSelectionShape = function (state) { + mxVertexHandler.prototype.createSelectionShape = function (state: IMxState) { const shape = this.graph.cellRenderer.createShape(state); shape.style = state.shape.style; @@ -67,8 +64,8 @@ function setPortHandler(graph: IMxGraph): void { } -function setPortValidationStyle(graph: IMxGraph) { - mxCellMarker.prototype.getMarkerColor = function (evt, state, isValid) { +function setPortValidationStyle(_graph: IMxGraph) { + mxCellMarker.prototype.getMarkerColor = function (_evt: PointerEvent, _state: IMxState, isValid: boolean) { return (isValid) ? "#1565c0" : "red"; }; mxCellHighlight.prototype.repaint = function () { @@ -87,7 +84,8 @@ function setPortValidationStyle(graph: IMxGraph) { this.shape.setCursor(this.state.shape.getCursor()); } - if (mxClient.IS_QUIRKS || document.documentMode == 8) { + // if (mxClient.IS_QUIRKS || document.documentMode == 8) { + if (mxClient.IS_QUIRKS) { if (this.shape.stroke == 'transparent') { this.shape.stroke = 'white'; this.shape.opacity = 1; @@ -103,15 +101,15 @@ function setPortValidationStyle(graph: IMxGraph) { // the code calculates graphX and graphY of mxMouseEvent // which involve intersection calculation in mxUtils.intersectsHotspot - mxUtils.convertPoint = function(container: HTMLDivElement, x: number, y: number) { - var origin = mxUtils.getScrollOrigin(container); - var offset = mxUtils.getOffset(container); + mxUtils.convertPoint = function (container: HTMLDivElement, x: number, y: number) { + var origin = mxUtils.getScrollOrigin(container); + var offset = mxUtils.getOffset(container); - offset.x -= origin.x; - offset.y -= origin.y; - - return new mxPoint(x - offset.x, y - offset.y); - } + offset.x -= origin.x; + offset.y -= origin.y; + + return new mxPoint(x - offset.x, y - offset.y); + } mxCellHighlight.prototype.createShape = function () { var shape = this.graph.cellRenderer.createShape(this.state); @@ -142,7 +140,7 @@ function setPortValidationStyle(graph: IMxGraph) { } -function setHotspot(graph: IMxGraph) { +function setHotspot(_graph: IMxGraph) { mxCellMarker.prototype.intersects = function (state: IMxState, me: IMxMouseEvent) { if (this.hotspotEnabled) { @@ -169,11 +167,11 @@ function setTooltips(graph: IMxGraph) { function setSelectionRecursively(graph: IMxGraph) { const selectModel = graph.getSelectionModel(); const setCells = selectModel.setCells; - selectModel.setCells = function (cells: ImxCell[]) { - setCells.call( selectModel, - cells.filter( cell => cell != null) - .map( cell => cell.getChildCount() ? [cell, ...cell.children.filter(port => graph.isPort(port))] : [cell] ) - .reduce((arr, cells) => arr.concat(cells) , []) + selectModel.setCells = function (cells: IMxCell[]) { + setCells.call(selectModel, + cells.filter(cell => cell != null) + .map(cell => cell.getChildCount() ? [cell, ...cell.children.filter(port => graph.isPort(port))] : [cell]) + .reduce((arr, cells) => arr.concat(cells), []) ); }; } @@ -196,7 +194,7 @@ export function initPort(graph: IMxGraph) { graph.cellsResizable = false; graph.extendParents = false; - graph.getLabel = function (cell: ImxCell) { + graph.getLabel = function (cell: IMxCell) { let label = mxGraph.prototype.getLabel.apply(this, arguments); // "supercall" if (this.isCellLocked(cell)) { return ""; } else if (this.isCellCollapsed(cell)) { @@ -213,10 +211,10 @@ export function initPort(graph: IMxGraph) { }; setTooltips(graph); // Removes the folding icon and disables any folding - graph.isCellFoldable = function (cell: ImxCell) { + graph.isCellFoldable = function (_cell: IMxCell) { return false; }; - graph.view.updateFixedTerminalPoint = function (edge, terminal, source, constraint) { + graph.view.updateFixedTerminalPoint = function (edge, terminal, source, _constraint) { mxGraphView.prototype.updateFixedTerminalPoint.apply(this, arguments); var pts = edge.absolutePoints; @@ -232,7 +230,7 @@ export function initPort(graph: IMxGraph) { graph.connectionHandler.isConnectableCell = (cell) => { return graph.isPort(cell); }; - mxEdgeHandler.prototype.isConnectableCell = (cell: ImxCell) => { + mxEdgeHandler.prototype.isConnectableCell = (cell: IMxCell) => { return graph.connectionHandler.isConnectableCell(cell); }; } diff --git a/src/types/action.ts b/src/types/action.ts index 7060ae7..22a1cf3 100644 --- a/src/types/action.ts +++ b/src/types/action.ts @@ -1,6 +1,6 @@ import { IClipboardContext, } from "../context/ClipboardContext"; +import { INavigator } from "../types/clipboard"; import { IMxGraph, IMxUndoManager } from "./mxGraph"; - export interface IMxAction { label?: string; shortcuts?: string[]; @@ -45,15 +45,15 @@ export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoM func: () => { clipboard.copyFuncForMenu(graph, clipboard.copy, clipboard.textInput); const text = clipboard.textInput.value; - navigator.clipboard.writeText(text) + (navigator as INavigator).clipboard.writeText(text) .then( - (result) => { + (result: void) => { // tslint:disable-next-line: no-console console.log("Successfully copied to clipboard", result); } ) .catch( - (err) => { + (err: ErrorEvent) => { // tslint:disable-next-line: no-console console.log("Error! could not copy text", err); }); @@ -64,15 +64,15 @@ export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoM func: () => { clipboard.cutFunc(graph, clipboard.copy, clipboard.textInput); const text = clipboard.textInput.value; - navigator.clipboard.writeText(text) + (navigator as INavigator).clipboard.writeText(text) .then( - (result) => { + (result: void) => { // tslint:disable-next-line: no-console console.log("Successfully copied to clipboard", result); } ) .catch( - (err) => { + (err: ErrorEvent) => { // tslint:disable-next-line: no-console console.log("Error! could not copy text", err); }); @@ -80,44 +80,46 @@ export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoM shortcuts: ["ctrl + x"] }, pasteHere: { - func: (trigger: {x: number; y: number}) => { - navigator.clipboard.readText() - .then( - // tslint:disable-next-line: promise-function-async - (result) => { - // tslint:disable-next-line: no-console - console.log("Successfully retrieved text from clipboard", result); - clipboard.textInput.focus(); // no listener - // tslint:disable-next-line: deprecation - clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput, trigger.x, trigger.y); - return Promise.resolve(result); - } - ) - .catch( - (err) => { - throw new Error("Error! read text from clipboard"); - }); + func: (trigger: { x: number; y: number }) => { + (navigator as INavigator).clipboard.readText() + .then( + // tslint:disable-next-line: promise-function-async + (result: string) => { + // tslint:disable-next-line: no-console + console.log("Successfully retrieved text from clipboard", result); + clipboard.textInput.focus(); // no listener + // tslint:disable-next-line: deprecation + clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput, trigger.x, trigger.y); + return Promise.resolve(result); + } + ) + .catch( + (err: ErrorEvent) => { + // tslint:disable-next-line: no-console + console.log("Error! could not copy text", err); + }); }, shortcuts: ["ctrl + v"] }, paste: { func: () => { - navigator.clipboard.readText() - .then( - // tslint:disable-next-line: promise-function-async - (result) => { - // tslint:disable-next-line: no-console - console.log("Successfully retrieved text from clipboard", result); - clipboard.textInput.focus(); // no listener - // tslint:disable-next-line: deprecation - clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput); - return Promise.resolve(result); - } - ) - .catch( - (err) => { - throw new Error("Error! read text from clipboard"); - }); + (navigator as INavigator).clipboard.readText() + .then( + // tslint:disable-next-line: promise-function-async + (result: string) => { + // tslint:disable-next-line: no-console + console.log("Successfully retrieved text from clipboard", result); + clipboard.textInput.focus(); // no listener + // tslint:disable-next-line: deprecation + clipboard.pasteFuncForMenu(result, graph, clipboard.copy, clipboard.textInput); + return Promise.resolve(result); + } + ) + .catch( + (err: ErrorEvent) => { + // tslint:disable-next-line: no-console + console.log("Error! read text from clipboard", err); + }); }, }, undo: { @@ -136,7 +138,7 @@ export function initActions(graph: IMxGraph, clipboard: IClipboardContext, undoM }, }, zoomOut: { - func: () => { + func: () => { graph.zoomOut(); }, }, diff --git a/src/types/clipboard.ts b/src/types/clipboard.ts new file mode 100644 index 0000000..3778fcd --- /dev/null +++ b/src/types/clipboard.ts @@ -0,0 +1,30 @@ +// for TS2339: Property 'clipboard' does not exist on type 'Navigator'. +// tslint:disable-next-line: no-empty-interface +export interface IClipboard extends EventTarget{ + writeText(newClipText: string): Promise; + readText(): Promise; + // Add any other methods you need here. +} + +interface INavigatorClipboard extends Navigator{ + // Only available in a secure context. + readonly clipboard: IClipboard; +} + +// tslint:disable-next-line: no-empty-interface +export interface INavigator extends INavigatorClipboard { } + +export interface IClipboardEvent extends ClipboardEvent { + dataTransfer: { + types: string; + getData(str: string): void; + }; +} + +// TS2339: Property 'mxGraphModel' does not exist on type 'Window'. + // tslint:disable: no-any +export interface IWindow extends Window { + mxGeometry: any; + mxGraphModel: any; + mxPoint: any; +} diff --git a/src/types/flow.ts b/src/types/flow.ts index 2078ba6..78ffba3 100644 --- a/src/types/flow.ts +++ b/src/types/flow.ts @@ -10,7 +10,7 @@ export interface ILayoutNode extends IDrawable { } export interface ICanvasNode extends IDrawable { - label: string; + label?: string; x: number; y: number; color?: string; @@ -28,10 +28,10 @@ export interface ICanvasNode extends IDrawable { export interface ICanvasEdge { source: number | string; - sourceAnchor: number | string; + sourceAnchor?: number | string; target: number | string; - targetAnchor: number | string; - index: number | string; + targetAnchor?: number | string; + index?: number | string; id: string; } diff --git a/src/types/mxGraph.ts b/src/types/mxGraph.ts index 936af00..a6a6d7a 100644 --- a/src/types/mxGraph.ts +++ b/src/types/mxGraph.ts @@ -5,6 +5,7 @@ import { IMxShape, IMxText, } from "./shapes"; + // tslint:disable-next-line: no-empty-interface export interface IEdge { @@ -20,29 +21,37 @@ export interface IParent { } -export interface ImxCell { +export interface IBasicCell { vertex: boolean; edge: boolean; - source?: ImxCell; - target?: ImxCell; - parent?: ImxCell; + parent?: IMxCell; geometry: IGeometry; mxObjectId: string; id: string; style: string; - edges: ImxCell[]; value: string; - children: ImxCell[]; + children: IMxCell[]; absolutePoints: IMxPoint[]; setConnectable(isConnectable: boolean): void; getStyle(): string; getChildCount(): number; setStyle(style: string): void; +} + +export interface IEdge extends IBasicCell{ + source: IMxCell; + target: IMxCell; removeFromTerminal(isSource: boolean): void; // removes the edge from its source or target terminal - getTerminal(isSource: boolean): ImxCell; // for edges + getTerminal(isSource: boolean): IMxCell; setAbsoluteTerminalPoint(point: IMxPoint, isSource: boolean): void; } +export interface INode extends IBasicCell { + edges: IEdge[]; +} + +export type IMxCell = IEdge | INode; + export interface IMxMenu { triggerX: number; triggerY: number; @@ -78,24 +87,25 @@ export interface IMxEventObject { } export interface IGraphModel { - cells: ImxCell[]; + cells: IMxCell[]; beginUpdate(): void; endUpdate(): void; - getTopmostCells(cells: ImxCell[]): ImxCell[]; - getCell(id: string): ImxCell; - getRoot(): ImxCell; - getChildCount(root: ImxCell): number; - getChildren(cell: ImxCell): ImxCell; - getValue(cell: ImxCell): string | null; - getGeometry(cell: ImxCell): IGeometry; - getTerminal(edge: ImxCell, isSource: boolean): ImxCell; // returns the source or target mxCell of the given edge depending on the value of the boolean parameter - setTerminal(edge: ImxCell, terminal: ImxCell, isSourse: boolean): void; // to current transaction - setTerminals(edge: ImxCell, source: ImxCell, target: ImxCell): void; // in a single transaction - setVisible(cell: ImxCell, visible: boolean): void; // to current transaction - addListener(action: string, listener: (sender: IGraphModel, evt: IMxEventObject) => void): void; - isVertex(cell: ImxCell): boolean; - isEdge(cell: ImxCell): boolean; - setValue(cell: ImxCell, value: string): void; + getTopmostCells(cells: IMxCell[]): IMxCell[]; + getCell(id: string): IMxCell; + getRoot(): IMxCell; + getChildCount(root: IMxCell): number; + getChildren(cell: IMxCell): IMxCell; + getChildAt(cell: IMxCell, index: number): IMxCell; + getValue(cell: IMxCell): string | null; + getGeometry(cell: IMxCell): IGeometry; + getTerminal(edge: IMxCell, isSource: boolean): IMxCell; // returns the source or target mxCell of the given edge depending on the value of the boolean parameter + setTerminal(edge: IMxCell, terminal: IMxCell, isSourse: boolean): void; // to current transaction + setTerminals(edge: IMxCell, source: IMxCell, target: IMxCell): void; // in a single transaction + setVisible(cell: IMxCell, visible: boolean): void; // to current transaction + addListener(action: string, listener: (_sender: IGraphModel, evt: IMxEventObject) => void): void; + isVertex(cell: IMxCell): boolean; + isEdge(cell: IMxCell): boolean; + setValue(cell: IMxCell, value: string): void; } interface IGeometry { @@ -114,17 +124,18 @@ interface IGeometry { interface IGraphView { scale: number; + graph: IMxGraph; translate: { x: number; y: number; }; - getState(cell: ImxCell): IMxState | null; - getTerminalPort(state: IMxState, terminal: ImxCell, isSource: boolean): IMxState; + getState(cell: IMxCell): IMxState | null; + getTerminalPort(state: IMxState, terminal: IMxCell, isSource: boolean): IMxState; addListener(action: string, listener: (sender: IGraphModel, evt: IMxEventObject) => void): void; - updateFixedTerminalPoint(edge: ImxCell, terminal: ImxCell, isSource: boolean, constraint?: IMxPoint[]): void; - getPerimeterFunction(terminal: ImxCell): () => void; - getRoutingCenterX(terminal: ImxCell): number; - getRoutingCenterY(terminal: ImxCell): number; + updateFixedTerminalPoint(edge: IEdge, terminal: INode, isSource: boolean, constraint?: IMxPoint[]): void; + getPerimeterFunction(terminal: IMxCell): () => void; + getRoutingCenterX(terminal: IMxCell): number; + getRoutingCenterY(terminal: IMxCell): number; } export interface IMxState { @@ -135,28 +146,34 @@ export interface IMxState { terminalDistance: number; // for edges segments: number[]; style: ICellStyle; - cell: ImxCell; + cell: IMxCell; cellBounds: IMxRectangle; text: IMxText; - getVisibleTerminal(isSource: boolean): ImxCell; + getVisibleTerminal(isSource: boolean): IMxCell; getVisibleTerminalState(isSource: boolean): IMxState; setVisibleTerminalState(terminalState: IMxState, isSource: boolean): void; } interface IMxSelectionModel { - cells: ImxCell[]; + cells: IMxCell[]; graph: IMxGraph; - setCell(cell: ImxCell): void; - setCells(cells: ImxCell[]): void; - addCell(cell: ImxCell): void; - addCells(cells: ImxCell[]): void; - removeCell(cell: ImxCell): void; - removeCells(cells: ImxCell[]): void; - selectRegion(rect: IMxRectangle, evt: any): void; - addListener(name: string, func: () => void): void; + setCell(cell: IMxCell): void; + setCells(cells: IMxCell[]): void; + addCell(cell: IMxCell): void; + addCells(cells: IMxCell[]): void; + removeCell(cell: IMxCell): void; + removeCells(cells: IMxCell[]): void; + selectRegion(rect: IMxRectangle, evt: IMxEventObject): void; + addListener(name: string, func: (sender: IMxSelectionModel, event: IMxEventObject) => void): void; } -export interface IStylesheet { +export interface IStyle extends IConfig { + edgeStyle: string; + fontStyle: string; +} + +export interface IStylesheet{ + createDefaultVertexStyle(): IStylesheet; putCellStyle(customName: string, customStyle: IStylesheet): void; /* @@ -164,6 +181,8 @@ export interface IStylesheet { * defaultStyle - Default style to be returned if no style can be found. */ getCellStyle(name: string, defaultStyle?: IStylesheet): IStylesheet; + getDefaultEdgeStyle(): IStyle; + getDefaultVertexStyle(): IStyle; } interface ICellStyle extends IConfig { @@ -188,7 +207,7 @@ export interface IMxMouseEvent { state: IMxState; getGraphX(): number; getGraphY(): number; - getCell(): ImxCell; + getCell(): IMxCell; getEvent(): PointerEvent; getState(): IMxState; } @@ -200,16 +219,26 @@ export interface IKeyHandler { bindControlShiftKey(keycode: number, func: () => void): void; } +// tslint:disable-next-line: no-empty-interface +export interface IMxRubberband{ + +} +// tslint:disable-next-line: no-empty-interface +export interface IMxConstraintHandler{ + isStateIgnored(state: IMxState, isSource: boolean): boolean; +} + export interface IMxGraph { popupMenuHandler: { autoExpand: boolean; - factoryMethod(menu: IMxMenu, cell: ImxCell | null, evt: () => {}): void; + factoryMethod(menu: IMxMenu, cell: IMxCell | null, evt: () => {}): void; }; container: HTMLDivElement; connectionHandler: { connectImage: IMxImage; graph: IMxGraph; - isConnectableCell(cell: ImxCell): boolean; + constraintHandler: IMxConstraintHandler; + isConnectableCell(cell: IMxCell): boolean; createEdgeState(me: IMxMouseEvent): IMxState; }; view: IGraphView; @@ -225,6 +254,10 @@ export interface IMxGraph { defaultEdgeStyle: object; currentEdgeStyle: object; keyHandler: IKeyHandler; + panDx: number; + panDy: number; + autoScroll: number; + autoExtend: boolean; addMouseListener(listener: { currentState: null | IMxState; mouseDown(sender: IMxGraph, me: IMxMouseEvent): void; @@ -232,56 +265,64 @@ export interface IMxGraph { mouseUp(sender: IMxGraph, me: IMxMouseEvent): void; }): void; createCurrentEdgeStyle(): string; - convertValueToString(terminal: ImxCell): string; - createEdge(parent: ImxCell | null, id: string | null, label: HTMLElement | null, source: ImxCell | null, target: ImxCell | null, style?: string): ImxCell; + convertValueToString(terminal: IMxCell): string; + createEdge(parent: IMxCell | null, id: string | null, label: HTMLElement | null, source: IMxCell | null, target: IMxCell | null, style?: string): IMxCell; getModel(): IGraphModel; getView(): IGraphView; - getDefaultParent(): ImxCell; - getCellGeometry(cell: ImxCell): IGeometry; - getCellStyle(cell: ImxCell): ICellStyle; - getLabel(cell: ImxCell): string; + getDefaultParent(): IMxCell; + getCellGeometry(cell: IMxCell): IGeometry; + getCellStyle(cell: IMxCell): ICellStyle; + getLabel(cell: IMxCell): string; getStylesheet(): IStylesheet; - getSelectionCells(): ImxCell[]; - getSelectionCell(): ImxCell; + getSelectionCells(): IMxCell[]; + getSelectionCell(): IMxCell; getSelectionModel(): IMxSelectionModel; - getTooltipForCell(cell: ImxCell): IMxToolTip; + getTooltipForCell(cell: IMxCell): IMxToolTip; getGraphBounds(): void; - insertVertex(parent: ImxCell, id?: string | null, value?: string, x?: number, y?: number, width?: number, height?: number, style?: string, isRelative?: boolean): ImxCell; - insertEdge(parent: ImxCell, id?: string | null, value?: string, source?: ImxCell, target?: ImxCell): ImxCell; - importCells(cells: ImxCell[], x: number, y: number, target: ImxCell): ImxCell[] | null; - scrollCellToVisible(cells: ImxCell[]): void; - setSelectionCells(cells: ImxCell[]): void; - setSelectionCell(cells: ImxCell[]): void; + insertVertex(parent: IMxCell, id?: string | null, value?: string, x?: number, y?: number, width?: number, height?: number, style?: string, isRelative?: boolean): IMxCell; + insertEdge(parent: IMxCell, id?: string | null, value?: string, source?: IMxCell, target?: IMxCell): IMxCell; + importCells(cells: IMxCell[], x: number, y: number, target: IMxCell): IMxCell[]; + scrollCellToVisible(cells: IMxCell[]): void; + setSelectionCells(cells: IMxCell[]): void; + setSelectionCell(cells: IMxCell[]): void; setTooltips(bl: boolean): void; setCellsResizable(bl: boolean): void; + setCellStyles(name: string, style: string, cell: IMxCell[]): void; setConnectable(bl: boolean): void; setAllowDanglingEdges(bl: boolean): void; setDisconnectOnMove(bl: boolean): void; selectCell(isNext: boolean, isParent?: boolean, isChild?: boolean): void; // - selectAll(parent: ImxCell, descendants: ImxCell[]): void; // select all children of the given parent cell - selectCells(vertices: ImxCell[], edges: ImxCell[], parent: ImxCell): void; + selectAll(parent: IMxCell, descendants: IMxCell[]): void; // select all children of the given parent cell + selectCells(vertices: IMxCell[], edges: IMxCell[], parent: IMxCell): void; selectPreviousCell(): void; selectParentCell(): void; selectChildCell(): void; setHtmlLabels(bl: boolean): void; setEnabled(bl: boolean): void; stopEditing(bl: boolean): void; + snap(value: number): number; isEnabled(): boolean; isEditing(): boolean; isSelectionEmpty(): boolean; - isCellLocked(target: ImxCell): boolean; - isCellFoldable(cell: ImxCell): boolean; - isCellCollapsed(cell: ImxCell): boolean; - removeCells(cells?: ImxCell[]): ImxCell[]; - resizeCell(cell: ImxCell, bounds: { x: number; y: number; width: number; height: number }, recurse?: boolean): void; - moveCells(cell: ImxCell, dx: number, dy: number): void; - cloneCells(cells: ImxCell[]): ImxCell[]; + isCellLocked(target: IMxCell): boolean; + isCellFoldable(cell: IMxCell): boolean; + isCellCollapsed(cell: IMxCell): boolean; + isCellSelected(cell: IMxCell): boolean; + isCellMovable(cell: IMxCell): boolean; + isCellsMovable(): boolean; + removeCells(cells?: IMxCell[]): IMxCell[]; + isDropEnabled(): boolean; + isGridEnabledEvent(evt: MouseEvent): boolean; + resizeCell(cell: IMxCell, bounds: { x: number; y: number; width: number; height: number }, recurse?: boolean): void; + moveCells(cell: IMxCell, dx: number, dy: number): void; + cloneCells(cells: IMxCell[]): IMxCell[]; // drill down - isPort(cell: ImxCell): boolean; - getTerminalForPort(portCell: ImxCell, isSource: boolean): ImxCell; + isPort(cell: IMxCell): boolean; + getTerminalForPort(portCell: IMxCell, isSource: boolean): IMxCell; zoomIn(): void; zoomOut(): void; fit(): void; zoomActual(): void; orderCells(isToBack: boolean): void; + scrollPointToVisible(x: number, y: number, isAutoExtend: boolean): void; } diff --git a/src/types/propsAPI.ts b/src/types/propsAPI.ts index 493ee41..28ac241 100644 --- a/src/types/propsAPI.ts +++ b/src/types/propsAPI.ts @@ -1,32 +1,65 @@ import { - ImxCell, + IMxCell, IMxGraph, } from "./mxGraph"; import { ICanvasData } from "./flow"; -export interface IModel { +// export interface IModel { +// size?: [number, number]; +// label?: string; +// color?: string; +// source?: string; // cell id +// target?: string; // cell id +// id?: string; +// shape?: string; +// edge?: boolean; +// } + +export interface IBasicModel { + size: [number, number]; + label?: string; + color?: string; + id: string; + shape: string; + edge: boolean; +} + +export interface INodeModel extends IBasicModel{ x: number; y: number; - size: [number, number]; - label: string; - color: string; + id: string; +} + +export interface IEdgeModel extends IBasicModel { source: string; // cell id target: string; // cell id id: string; - shape: string; - edge: boolean; +} + +export type ICellModel = INodeModel | IEdgeModel; + +// export type NonNullable = T extends null | undefined ? never : T; + +// export type NonNullablePropertyKeys = { +// [P in keyof T]: null extends T[P] ? never : P +// }[keyof T] + +export type IModelEditor = Partial; + +export function isEdgeModel(cell: ICellModel): cell is IEdgeModel { + return (cell as IEdgeModel).edge; } export interface IPropsAPI { graph: IMxGraph; executeCommand(command: string): void; - find(id: string): ImxCell; - getSelected(): ImxCell[]; + find(id: string): IMxCell; + getSelected(): IMxCell[]; read(data: ICanvasData): void; save(): object; - getCellModel(cell: ImxCell): IModel; - add(name: "node" | "edge", model: IModel): void; - update(cell: ImxCell, model: IModel): void; - remove(cell: ImxCell): void; + getCellModel(cell: IMxCell): ICellModel; + add(model: ICellModel): void; + update(cell: IMxCell, model: IModelEditor): void; + remove(cell: IMxCell): void; } diff --git a/src/types/shapes.ts b/src/types/shapes.ts index c6e1615..783093c 100644 --- a/src/types/shapes.ts +++ b/src/types/shapes.ts @@ -21,10 +21,11 @@ export interface IConfig { } export interface IShape { - style: string; + style: string; } export interface IMxShape { + style: IConfig; apply(state: IMxState): void; redraw(): void; } @@ -35,6 +36,10 @@ export interface IMxRectangleShape extends IMxShape { bounds: IMxRectangle; } +export interface IMxEllipse extends IMxShape { + style: IConfig; +} + export interface IMxText extends IMxShape { style: IConfig; background: string; diff --git a/stories/index.stories.tsx b/stories/index.stories.tsx index baae9a1..18356cb 100644 --- a/stories/index.stories.tsx +++ b/stories/index.stories.tsx @@ -6,9 +6,6 @@ import { CanvasMenu, CanvasPanel, Command, - RegisterCommand, - IPropsAPI, - withPropsApi, ContextMenu, DetailPanel, EdgeMenu, @@ -16,16 +13,20 @@ import { Flow, Item, ItemPanel, + Minimap, MxGraph, NodePanel, - PropsComponent, + RegisterCommand, RegisterNode, - TextEditor, Toolbar, ToolCommand, VertexMenu, - Minimap + withPropsApi } from "../src/index"; + +import { + IPropsAPI, +} from "../src/types/propsAPI"; import "./index.scss"; const data = { @@ -61,6 +62,133 @@ const data = { }; +interface IProps { + propsAPI: IPropsAPI; + data: ICanvasData; +} + +// tslint:disable-next-line: max-classes-per-file +class TestComponent extends React.PureComponent { + constructor(props: IProps) { + super(props); + this.state = { + value: "", + cellV: "no find", + }; + } + + public render(): React.ReactNode { + return ( +
+

test with props api component

+ + + + + + + +
+
+ +
+
+ +
+ {this.state.cellV} +
+
+ ); + } + + public handleChange = (event: React.SyntheticEvent) => { + this.setState({ value: event.target.value }); + } + + public handleSubmit = (event) => { + event.preventDefault(); + const cell = this.props.propsAPI.find(this.state.value); + const val = cell ? cell.value : "no found"; + this.setState({ cellV: val }); + } + + public getSelectionStyle = () => { + const cell = this.props.propsAPI.getSelected(); + const graph = this.props.propsAPI.graph; + // console.log(cell[0], graph.getCellStyle(cell[0])); + } + + public testUpdateCell = () => { + const cell = this.props.propsAPI.find("22"); + if (!cell) { + return; + } + this.props.propsAPI.update(cell, { + size: [30, 70], + x: cell.geometry.x - 10, + y: cell.geometry.y - 10, + label: "test", + color: "#CCCCCC", + }); + } + + public testRemoveCell = () => { + const cell = this.props.propsAPI.find("20"); + this.props.propsAPI.remove(cell); + } + + public testExeCopy = () => { + this.props.propsAPI.executeCommand("copy"); + } + + public testReadData = () => { + this.props.propsAPI.read(this.props.data); + } + + public testSaveData = () => { + // tslint:disable-next-line: no-console + console.log(this.props.propsAPI.save()); + } + + public testAddCell = () => { + this.props.propsAPI.add( + { + size: [100, 30], + shape: "rounded", + label: "add1", + x: 355, + y: 255, + id: "20", + edge: false, + }); + this.props.propsAPI.add( + { + size: [100, 30], + shape: "rounded", + label: "add2", + x: 355, + y: 355, + id: "22", + edge: false, + }); + this.props.propsAPI.add( + { + source: "20", + target: "22", + id: "21", + edge: true, + }); + } +} + +// tslint:disable-next-line: export-name +const PropsComponent = withPropsApi(TestComponent); + + + storiesOf("Flow", module) .add("Basic flow", () => { const data = { @@ -131,7 +259,7 @@ storiesOf("Flow", module) - + @@ -230,43 +358,6 @@ storiesOf("Flow", module)
); - }).add("RegisterShape", () => { - return ( -
- - - Rounded - Rounded2 - - - - - -
- ); - }).add("textEditor", () => { - return ( -
- - - - - - - - - - - - -
- ); }).add("withPropsAPI", () => { const data2 = { nodes: [{ @@ -307,6 +398,26 @@ storiesOf("Flow", module)
); + }).add("RegisterShape", () => { + return ( +
+ + + Rounded + Rounded2 + + + + + +
+ ); }).add("registerCommand", () => { interface IProps { diff --git a/test/__snapshots__/index.spec.tsx.snap b/test/__snapshots__/index.spec.tsx.snap index 4e37e70..7678bcc 100644 --- a/test/__snapshots__/index.spec.tsx.snap +++ b/test/__snapshots__/index.spec.tsx.snap @@ -11,6 +11,13 @@ exports[`Storyshots Flow Basic flow 1`] = ` >
@@ -674,6 +681,13 @@ exports[`Storyshots Flow Command 1`] = ` >
@@ -1306,7 +1320,7 @@ exports[`Storyshots Flow Command 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -1670,7 +1684,7 @@ exports[`Storyshots Flow Command 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -2034,7 +2048,7 @@ exports[`Storyshots Flow Command 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -2698,7 +2712,7 @@ exports[`Storyshots Flow Command 1`] = ` } > " - _class + WithNameProps " Component @@ -2714,7 +2728,7 @@ exports[`Storyshots Flow Command 1`] = ` } > " - _class + WithNameProps " Component @@ -2730,7 +2744,7 @@ exports[`Storyshots Flow Command 1`] = ` } > " - _class + WithNameProps " Component @@ -2754,6 +2768,13 @@ exports[`Storyshots Flow Context menu 1`] = ` >
@@ -3355,7 +3376,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -3947,7 +3968,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps > @@ -4539,7 +4560,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > < - _class + WithNameProps - paste + pasteHere " @@ -5194,7 +5215,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > </ - _class + WithNameProps > @@ -5352,7 +5373,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > " - _class + WithNameProps " Component @@ -5368,7 +5389,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > " - _class + WithNameProps " Component @@ -5384,7 +5405,7 @@ exports[`Storyshots Flow Context menu 1`] = ` } > " - _class + WithNameProps " Component @@ -5409,17 +5430,42 @@ exports[`Storyshots Flow Item Panel 1`] = ` >
-
+
ellipse
-
+
rhombus
-
+
cloud
@@ -6399,7 +6445,7 @@ exports[`Storyshots Flow Item Panel 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -6763,7 +6809,7 @@ exports[`Storyshots Flow Item Panel 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -7069,7 +7115,7 @@ exports[`Storyshots Flow Item Panel 1`] = ` } > < - _class + WithNameProps </ - _class + WithNameProps >
@@ -7649,7 +7695,7 @@ exports[`Storyshots Flow Item Panel 1`] = ` } > " - _class + WithNameProps " Component @@ -7665,7 +7711,7 @@ exports[`Storyshots Flow Item Panel 1`] = ` } > " - _class + WithNameProps " Component @@ -7681,7 +7727,7 @@ exports[`Storyshots Flow Item Panel 1`] = ` } > " - _class + WithNameProps " Component @@ -7707,15 +7753,34 @@ exports[`Storyshots Flow RegisterShape 1`] = `
-
+
Rounded
-
+
Rounded2
@@ -9608,6 +9673,13 @@ exports[`Storyshots Flow Toolbar 1`] = ` >
@@ -11115,6 +11187,13 @@ exports[`Storyshots Flow registerCommand 1`] = ` >

select a cell then press arrowright to move it to right @@ -11836,7 +11915,7 @@ exports[`Storyshots Flow registerCommand 1`] = ` } > < - _class + WithPropsApi " - _class + WithPropsApi " Component @@ -11983,7 +12062,7 @@ exports[`Storyshots Flow registerCommand 1`] = `

`; -exports[`Storyshots Flow textEditor 1`] = ` +exports[`Storyshots Flow withPropsAPI 1`] = `
-
-

- no selection -

-
-
-
-
-
-
- -
-

- Story Source -

-
-          
-
-
- - < - div - - - - > - -
-
-
- - < - MxGraph - - - - > - -
-
- - < - Flow - - - - - - data - - - = - - { - - { - - - nodes - - - : - - [ - - - { - - -
- - -
- - type - -
- : - - 'node' - - , - - -
- - -
- - size - -
- : - - [ - - - 70 - - - , - - - 70 - - - ] - - , - - -
- - -
- - shape - -
- : - - 'rounded' - - , - - -
- - -
- … -
- -
- -
- } -
-
- , - - - { - - -
- - -
- - type - -
- : - - 'node' - - , - - -
- - -
- - size - -
- : - - [ - - - 70 - - - , - - - 70 - - - ] - - , - - -
- - -
- - shape - -
- : - - 'rounded2' - - , - - -
- - -
- … -
- -
- -
- } -
-
- ] -
- , - - - edges - - - : - - [ - - - { - - -
- - -
- - source - -
- : - - 'ea1184e8' - - , - - -
- - -
- - sourceAnchor - -
- : - - 2 - - , - - -
- - -
- - target - -
- : - - '481fbb1a' - - , - - -
- - -
- … -
- -
- -
- } -
-
- ] -
- } -
- } -
-
- -
-
- - /> - -
-
-
- - < - DetailPanel - - - - > - -
-
-
- - < - _class - - - - > - -
-
- - < - TextEditor - - - - /> - -
-
- - </ - _class - > - -
-
-
-
- - < - _class - - - - > - -
-
- - < - TextEditor - - - - /> - -
-
- - </ - _class - > - -
-
-
- - < - _class - - - - /> - -
-
- - </ - DetailPanel - > - -
-
-
- - </ - MxGraph - > - -
-
-
- - </ - div - > - -
-
-
- -
-
-
-

- Prop Types -

-
-

- " - DetailPanel - " Component -

- - No propTypes defined! - -
-
-

- " - Flow - " Component -

- - No propTypes defined! - -
-
-

- " - MxGraph - " Component -

- - No propTypes defined! - -
-
-

- " - TextEditor - " Component -

- - No propTypes defined! - -
-
-

- " - _class - " Component -

- - No propTypes defined! - -
-
-

- " - _class - " Component -

- - No propTypes defined! - -
-
-

- " - _class - " Component -

- - No propTypes defined! - -
-
-
-
-
-`; - -exports[`Storyshots Flow withPropsAPI 1`] = ` -
-
-
-
-

@@ -13697,7 +12743,7 @@ exports[`Storyshots Flow withPropsAPI 1`] = ` } > < - _class + WithPropsApi @@ -14275,7 +13321,7 @@ exports[`Storyshots Flow withPropsAPI 1`] = ` } > " - _class + WithPropsApi " Component From 467b8472bb32fc8364e461d199688a9f3841a24d Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 15:10:25 +0800 Subject: [PATCH 06/12] fix panel reaction --- demo/src/components/FlowDetailForm.tsx | 95 +++++++++++++++++++++++-- demo/src/components/FlowDetailPanel.tsx | 7 +- src/components/DetailPanel.tsx | 33 ++++++++- src/components/Item.tsx | 2 +- src/components/MxGraph.tsx | 14 +++- src/components/Panel.tsx | 22 ++++-- src/components/WithPropsApi.tsx | 3 +- src/types/mxGraph.ts | 4 +- src/types/propsAPI.ts | 2 + src/types/shapes.ts | 2 + 10 files changed, 160 insertions(+), 24 deletions(-) diff --git a/demo/src/components/FlowDetailForm.tsx b/demo/src/components/FlowDetailForm.tsx index c28c946..12e4ee8 100644 --- a/demo/src/components/FlowDetailForm.tsx +++ b/demo/src/components/FlowDetailForm.tsx @@ -1,19 +1,23 @@ import * as React from "react"; import { withPropsApi } from "../../../src/index"; import { ICanvasData } from "../../../src/types/flow"; -import { IPropsAPI } from "../../../src/types/propsAPI"; +import { IPropsAPI, IEdgeModel } from "../../../src/types/propsAPI"; interface IProps { propsAPI: IPropsAPI; + name: string; } import * as Fabric from "office-ui-fabric-react"; -import { StackItem } from "office-ui-fabric-react"; + import { IMxCell } from "../../../src/types/mxGraph"; const { TextField, Stack, + StackItem, + Label, + Text, } = Fabric; export class DetailForm extends React.PureComponent { @@ -31,14 +35,95 @@ export class DetailForm extends React.PureComponent { this._isEditing = false; } public render(): React.ReactNode { + console.log("render"); + const { name } = this.props; return ( - + {name === "node" && this.renderNodeDetail()} + {name === "edge" && this.renderEdgeDetail()} + {name === "port" && this.renderPortDetail()} + {name === "canvas" && this.renderCanvasDetail()} + + ); + } + + public renderNodeDetail = () => { + const { propsAPI } = this.props; + const model = propsAPI.getCellModel(this.cell); + console.log(model); + return [ + ( + - + ), + ( + + + {model.id} + + ) + ]; + } + + public renderEdgeDetail = () => { + const { propsAPI } = this.props; + const model = propsAPI.getCellModel(this.cell); + console.log(model); + return [ + ( + + + + ), + ( + + + {model.id} + + {(model as IEdgeModel).source} + + {(model as IEdgeModel).target} + + {(model as IEdgeModel).sourcePort} + + {(model as IEdgeModel).targetPort} + + ) + ]; + } + + public renderPortDetail = () => { + const { propsAPI } = this.props; + const model = propsAPI.getCellModel(this.cell); + console.log(model); + console.log(propsAPI.graph.getTerminalForPort(this.cell, false)); + console.log(propsAPI.graph.getTerminalForPort(this.cell, true)); + return [ + ( + + + + ), + ( + + + {model.id} + + ) + ]; + } + + public renderCanvasDetail = () => { + const { propsAPI } = this.props; + console.log(propsAPI); + return ( + + {"canvas"} + ); } + private readonly _onChange = (event) => { this.setState({ value: event.target.value }); } @@ -54,7 +139,7 @@ export class DetailForm extends React.PureComponent { if (!cell) { throw new Error("no cell to get value"); } - update(cell, {label: this.state.value}); + update(cell, { label: this.state.value }); this._isEditing = false; } private readonly _getCellValue = () => { diff --git a/demo/src/components/FlowDetailPanel.tsx b/demo/src/components/FlowDetailPanel.tsx index a24a855..069910f 100644 --- a/demo/src/components/FlowDetailPanel.tsx +++ b/demo/src/components/FlowDetailPanel.tsx @@ -4,7 +4,6 @@ import { EdgePanel, NodePanel, PortPanel, - TextEditor, } from "../../../src/index"; import { @@ -15,13 +14,13 @@ export const FlowDetailPanel = () => { return ( - + - + - + ); diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index f00cf1f..2629a2d 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import * as mxGraphJs from "mxgraph-js"; const { - mxEvent + mxEvent, } = mxGraphJs; import { @@ -17,7 +17,8 @@ import { PanelContext, } from "../context/PanelContext"; -export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> { +// tslint:disable-next-line: use-react-pure-component +export class DetailPanel extends React.Component<{}, { cells?: IMxCell[] }> { public _first: boolean; constructor(props: {}) { super(props); @@ -28,6 +29,22 @@ export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> } + // public shouldComponentUpdate(_nextProps: {}, nextState: { cells?: IMxCell[]}): boolean { + // if (this.state.cells && nextState.cells) { + // if (this.state.cells.length === nextState.cells.length) { + // for (let i = 0; i < this.state.cells.length; i += 1) { + // if (this.state.cells[i] !== nextState.cells[i]) { + // return true; + // } + // } + // return false; + // } + // else { return true; } + // } else { + // return this.state.cells !== nextState.cells; + // } + // } + public render(): React.ReactNode { // console.log("render"); return ( @@ -40,7 +57,9 @@ export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> this._setListener(graph); this._first = false; } - const name = this._getName(graph, this.state.cells); + const name = this._getName(graph, graph.getSelectionCells()); + // console.log("render root") + // console.log(this.state.cells); return (

@@ -61,7 +80,15 @@ export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> // console.log(_sender, _evt); // console.log(graph.getSelectionCells()[0], graph.getDefaultParent()); this.setState({ cells: graph.getSelectionCells() }); + // this.forceUpdate(); }); + // const that = this; + // const selectChange = mxGraphSelectionModel.prototype.changeSelection; + // graph.getSelectionModel().changeSelection = function () { + // selectChange.apply(this, arguments); + + // console.log("change"); + // }; } private readonly _getName = (graph: IMxGraph, cells?: IMxCell[]): string => { diff --git a/src/components/Item.tsx b/src/components/Item.tsx index 5165538..5b890d7 100644 --- a/src/components/Item.tsx +++ b/src/components/Item.tsx @@ -74,7 +74,7 @@ export class Item extends React.PureComponent{ private readonly insertNode = (graph: IMxGraph, _evt: PointerEvent, target: IMxCell, x: number, y: number): void => { const label = this.props.model && this.props.model.label ? this.props.model.label : "none"; - // tslint:disable-next-line: newline-per-chained-call + const shape = this.props.shape; const tmp = this.props.size ? this.props.size.split("*") .map((s) => parseInt(s, 10)) : [100, 70]; diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index 40e7e9a..e617d23 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -263,6 +263,18 @@ export class MxGraph extends React.PureComponent<{}, IState> { } private readonly insertEdge = (parent: IMxCell, graph: IMxGraph, edge: ICanvasEdge, source: IMxCell, target: IMxCell): IMxCell => { + + const sourceAnchor = edge.sourceAnchor; + const targetAnchor = edge.targetAnchor; + if (sourceAnchor !== undefined && targetAnchor !== undefined) { + const port1 = graph.getModel() + .getChildAt(source, Number(sourceAnchor)); + const port2 = graph.getModel() + .getChildAt(target, Number(targetAnchor)); + if (port1 && port2) { + return graph.insertEdge(parent, edge.id, "", port1, port2); + } + } return graph.insertEdge(parent, edge.id, "", source, target); } @@ -286,7 +298,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { const target = vertexes.find((v) => v.id === edge.target); if (source && target) { - graph.insertEdge(parent, edge.id, "", source.vertex, target.vertex); + this.insertEdge(parent, graph, edge, source.vertex, target.vertex); } }); } finally { diff --git a/src/components/Panel.tsx b/src/components/Panel.tsx index 7ffafb2..8d97068 100644 --- a/src/components/Panel.tsx +++ b/src/components/Panel.tsx @@ -4,26 +4,34 @@ import { PanelContext, } from "../context/PanelContext"; -class Panel extends React.PureComponent<{name: string}> { +class Panel extends React.PureComponent<{ name: string }> { + public key?: string; + public render(): React.ReactNode { + // console.log("render"); + // const childrenWithProps = React.Children.map(this.props.children, (child) => React.cloneElement(child, {})) return ( {(value: IPanelContext) => { const { name, cells, } = value; - + this.key = cells && cells.length ? cells[0].id : undefined; if (name && cells && name === this.props.name) { - return ( -
- {this.props.children} -
- ); + // console.log("render panel", this.props.children); + if (React.isValidElement(this.props.children)) { + return ( +
+ {React.cloneElement(this.props.children, {key: this.key, })} +
+ ); + } } return null; }}
); } + } import { diff --git a/src/components/WithPropsApi.tsx b/src/components/WithPropsApi.tsx index 93df361..dff298b 100644 --- a/src/components/WithPropsApi.tsx +++ b/src/components/WithPropsApi.tsx @@ -60,7 +60,6 @@ export const withPropsApi = (WrappedComponent: any) => getCellModel: (cell: IMxCell) => { const geo = graphModel.getGeometry(cell); const style = graph.getCellStyle(cell); - // tslint:disable-next-line: no-any const cellData: any = { id: cell.id, @@ -73,6 +72,8 @@ export const withPropsApi = (WrappedComponent: any) => if (graphModel.isEdge(cell)) { cellData.source = (cell as IEdge).source.id; cellData.target = (cell as IEdge).target.id; + cellData.sourcePort = style.sourcePort; + cellData.targetPort = style.targetPort; return (cellData as IEdgeModel); } else { cellData.x = geo.x; diff --git a/src/types/mxGraph.ts b/src/types/mxGraph.ts index a6a6d7a..3177724 100644 --- a/src/types/mxGraph.ts +++ b/src/types/mxGraph.ts @@ -280,7 +280,7 @@ export interface IMxGraph { getTooltipForCell(cell: IMxCell): IMxToolTip; getGraphBounds(): void; insertVertex(parent: IMxCell, id?: string | null, value?: string, x?: number, y?: number, width?: number, height?: number, style?: string, isRelative?: boolean): IMxCell; - insertEdge(parent: IMxCell, id?: string | null, value?: string, source?: IMxCell, target?: IMxCell): IMxCell; + insertEdge(parent: IMxCell, id?: string | null, value?: string, source?: IMxCell, target?: IMxCell, style?: string): IMxCell; importCells(cells: IMxCell[], x: number, y: number, target: IMxCell): IMxCell[]; scrollCellToVisible(cells: IMxCell[]): void; setSelectionCells(cells: IMxCell[]): void; @@ -318,7 +318,7 @@ export interface IMxGraph { cloneCells(cells: IMxCell[]): IMxCell[]; // drill down isPort(cell: IMxCell): boolean; - getTerminalForPort(portCell: IMxCell, isSource: boolean): IMxCell; + getTerminalForPort(portCell: IMxCell, source: boolean/* if the cell is source or target port*/): IMxCell; zoomIn(): void; zoomOut(): void; fit(): void; diff --git a/src/types/propsAPI.ts b/src/types/propsAPI.ts index 28ac241..8cc69e2 100644 --- a/src/types/propsAPI.ts +++ b/src/types/propsAPI.ts @@ -34,6 +34,8 @@ export interface INodeModel extends IBasicModel{ export interface IEdgeModel extends IBasicModel { source: string; // cell id target: string; // cell id + sourcePort: string; // cell id + targetPort: string; // cell id id: string; } diff --git a/src/types/shapes.ts b/src/types/shapes.ts index 783093c..847975e 100644 --- a/src/types/shapes.ts +++ b/src/types/shapes.ts @@ -18,6 +18,8 @@ export interface IConfig { textOpacity?: number; // 0~100 fontFamily?: string; points?: number[][]; + sourcePort?: number; + targetPort?: number; } export interface IShape { From 4dd0983c732735fae4ecf64ca238de97b7e9aaaa Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 15:36:18 +0800 Subject: [PATCH 07/12] . --- package.json | 3 ++- src/components/Command.tsx | 2 +- src/components/DetailPanel.tsx | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 15da439..7866cc4 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "dependencies": { "@storybook/react": "^5.1.9", "eslint": "^6.0.1", - "mxgraph-js": "^1.0.1" + "mxgraph-js": "^1.0.1", + "office-ui-fabric-react": "^7.28.1" } } diff --git a/src/components/Command.tsx b/src/components/Command.tsx index 41c1334..d6d94dc 100644 --- a/src/components/Command.tsx +++ b/src/components/Command.tsx @@ -1,7 +1,7 @@ import * as React from "react"; // @ts-ignore -import * as mxGraphJs from "mxgraph-js"; +import * as mxGraph from "mxgraph"; import { IMenuItemContext, diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index 2629a2d..83f86dc 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -17,8 +17,7 @@ import { PanelContext, } from "../context/PanelContext"; -// tslint:disable-next-line: use-react-pure-component -export class DetailPanel extends React.Component<{}, { cells?: IMxCell[] }> { +export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> { public _first: boolean; constructor(props: {}) { super(props); From 2b7eb79958ab01983b3f97ff2d92276f7f0adb41 Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 16:31:35 +0800 Subject: [PATCH 08/12] upgrade mxgraph to v4.0.4 --- package.json | 1 + src/components/Command.tsx | 3 --- src/components/ContextMenu.tsx | 4 ++-- src/components/DetailPanel.tsx | 11 ++++++---- src/components/Flow.tsx | 15 ++++++++------ src/components/Item.tsx | 12 +++++++---- src/components/ItemPanel.tsx | 3 --- src/components/Minimap.tsx | 4 ++-- src/components/MxGraph.tsx | 14 ++++++------- src/components/RegisterCommand.tsx | 2 -- src/components/RegisterNode.tsx | 6 +++--- src/components/ToolCommand.tsx | 3 --- src/components/WithNameProps.tsx | 9 -------- src/components/WithPropsApi.tsx | 10 +++------ src/context/ClipboardContext.ts | 10 ++++----- src/mxgraph.ts | 33 ++++++++++++++++++++++++++++++ src/settings/edge.ts | 17 ++++++++------- src/settings/guide.ts | 6 +++--- src/settings/init.ts | 25 +++++++++++----------- src/settings/port.ts | 20 +++++++++--------- 20 files changed, 113 insertions(+), 95 deletions(-) create mode 100644 src/mxgraph.ts diff --git a/package.json b/package.json index 7866cc4..1050f20 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "dependencies": { "@storybook/react": "^5.1.9", "eslint": "^6.0.1", + "mxgraph": "^4.0.4", "mxgraph-js": "^1.0.1", "office-ui-fabric-react": "^7.28.1" } diff --git a/src/components/Command.tsx b/src/components/Command.tsx index d6d94dc..354a1d2 100644 --- a/src/components/Command.tsx +++ b/src/components/Command.tsx @@ -1,8 +1,5 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraph from "mxgraph"; - import { IMenuItemContext, MenuItemContext, diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 3b1203b..9bf62ff 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -2,10 +2,10 @@ import * as mxGraphJs from "mxgraph-js"; import * as React from "react"; -const { +import { mxEvent, mxUtils, -} = mxGraphJs; +} from "../mxgraph"; import { IMxGraphContext, diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index 83f86dc..7772f2d 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -1,11 +1,14 @@ import * as React from "react"; // @ts-ignore -import * as mxGraphJs from "mxgraph-js"; +// import * as mxGraphJs from "mxgraph-js"; -const { - mxEvent, -} = mxGraphJs; +// const { +// mxEvent, +// } = mxGraphJs; +import { + mxEvent +} from "../mxgraph"; import { IMxGraphContext, diff --git a/src/components/Flow.tsx b/src/components/Flow.tsx index 32b8bb1..0d31915 100644 --- a/src/components/Flow.tsx +++ b/src/components/Flow.tsx @@ -3,8 +3,15 @@ import { ICanvasData, } from "../types/flow"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; +// // @ts-ignore +// import * as mxGraphJs from "mxgraph-js"; + +// const { +// mxGraph, +// } = mxGraphJs; +// import mxGraphFactory from 'mxgraph'; +// const { mxClient, mxGraphModel, mxGraph } = new mxGraphFactory(); +import { mxGraph } from "../mxgraph"; import { IMxGraphContext, @@ -22,10 +29,6 @@ interface IFlowState { graph?: IMxGraph; } -const { - mxGraph, -} = mxGraphJs; - export class Flow extends React.PureComponent { private readonly _containerRef = React.createRef(); private _setGraph?: (graph: IMxGraph) => void; diff --git a/src/components/Item.tsx b/src/components/Item.tsx index 5b890d7..2f1d55f 100644 --- a/src/components/Item.tsx +++ b/src/components/Item.tsx @@ -1,11 +1,15 @@ import * as React from "react"; // @ts-ignore -import * as mxGraphJs from "mxgraph-js"; +// import * as mxGraphJs from "mxgraph-js"; -const { - mxUtils, - } = mxGraphJs; +// const { +// mxUtils, +// } = mxGraphJs; + +import { + mxUtils +} from "../mxgraph"; import { IMxGraphContext, diff --git a/src/components/ItemPanel.tsx b/src/components/ItemPanel.tsx index a052c27..615739e 100644 --- a/src/components/ItemPanel.tsx +++ b/src/components/ItemPanel.tsx @@ -1,8 +1,5 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; - export class ItemPanel extends React.PureComponent { public render(): React.ReactNode { diff --git a/src/components/Minimap.tsx b/src/components/Minimap.tsx index bddbc55..dafe2de 100644 --- a/src/components/Minimap.tsx +++ b/src/components/Minimap.tsx @@ -8,9 +8,9 @@ import { } from "../context/MxGraphContext"; import { IMxGraph } from "../types/mxGraph"; -const { +import { mxOutline, -} = mxGraphJs; +} from "../mxgraph"; interface IMinimapProps { width?: string; diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index e617d23..a5ce5ab 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -25,18 +25,18 @@ import { } from "../types/mxGraph"; import { ICustomShape, } from "../types/shapes"; -const { +import { mxClient, - mxUtils, + mxConstants, mxEvent, - mxGraphModel, mxGeometry, - mxPoint, - mxUndoManager, + mxGraphModel, mxKeyHandler, - mxConstants, + mxPoint, mxRubberband, -} = mxGraphJs; + mxUndoManager, + mxUtils, +} from "../mxgraph"; (window as IWindow).mxGeometry = mxGeometry; (window as IWindow).mxGraphModel = mxGraphModel; diff --git a/src/components/RegisterCommand.tsx b/src/components/RegisterCommand.tsx index 9904066..5759152 100644 --- a/src/components/RegisterCommand.tsx +++ b/src/components/RegisterCommand.tsx @@ -1,7 +1,5 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext, diff --git a/src/components/RegisterNode.tsx b/src/components/RegisterNode.tsx index ac1b723..2b06632 100644 --- a/src/components/RegisterNode.tsx +++ b/src/components/RegisterNode.tsx @@ -3,12 +3,12 @@ import * as React from "react"; // @ts-ignore import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext } from "../context/MxGraphContext"; -const { +import { mxCellRenderer, - mxRectangleShape, mxEllipse, + mxRectangleShape, mxUtils, -} = mxGraphJs; +} from "../mxgraph"; import { IConfig, diff --git a/src/components/ToolCommand.tsx b/src/components/ToolCommand.tsx index 8cb614a..1a24684 100644 --- a/src/components/ToolCommand.tsx +++ b/src/components/ToolCommand.tsx @@ -1,8 +1,5 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; - import { IMxGraphContext, MxGraphContext } from "../context/MxGraphContext"; export class ToolCommand extends React.PureComponent<{ name: string; text?: string }> { diff --git a/src/components/WithNameProps.tsx b/src/components/WithNameProps.tsx index b693f12..cea7c12 100644 --- a/src/components/WithNameProps.tsx +++ b/src/components/WithNameProps.tsx @@ -1,14 +1,5 @@ import * as React from "react"; -// // tslint:disable-next-line: export-name -// export function createMenu(MenuComponent, name): React.PureComponent { -// return class extends React.PureComponent { -// public render(): React.ReactNode { -// return ; -// } -// }; -// } - // const withNameProps =

(PanelComponent: React.ComponentType

, name: string) => { // return ( // class WithNameProps extends React.PureComponent

{ diff --git a/src/components/WithPropsApi.tsx b/src/components/WithPropsApi.tsx index dff298b..5c73fcd 100644 --- a/src/components/WithPropsApi.tsx +++ b/src/components/WithPropsApi.tsx @@ -1,8 +1,9 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext } from "../context/MxGraphContext"; +import { + mxConstants, +} from "../mxgraph"; import { IEdge, IMxCell, } from "../types/mxGraph"; import { ICellModel, @@ -12,11 +13,6 @@ import { IPropsAPI, isEdgeModel, } from "../types/propsAPI"; -const { - mxConstants, -} = mxGraphJs; - -// function isEdge(cell: ImxCell) // tslint:disable-next-line: export-name no-any export const withPropsApi = (WrappedComponent: any) => diff --git a/src/context/ClipboardContext.ts b/src/context/ClipboardContext.ts index 0fbddd6..95e1455 100644 --- a/src/context/ClipboardContext.ts +++ b/src/context/ClipboardContext.ts @@ -1,13 +1,13 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; import * as React from "react"; -import { IMxCell, IMxGraph } from "../types/mxGraph"; -const { - mxUtils, +import { mxClipboard, - mxGraphModel, mxCodec, -} = mxGraphJs; + mxGraphModel, + mxUtils, +} from "../mxgraph"; +import { IMxCell, IMxGraph } from "../types/mxGraph"; import { IClipboardEvent, diff --git a/src/mxgraph.ts b/src/mxgraph.ts new file mode 100644 index 0000000..b59a422 --- /dev/null +++ b/src/mxgraph.ts @@ -0,0 +1,33 @@ +// @ts-ignore +import mxGraphFactory from "mxgraph"; +// tslint:disable-next-line: export-name +export const { + mxEvent, + mxUtils, + mxConstraintHandler, + mxGraph, + mxPoint, + mxEllipse, + mxConstants, + mxConnectionHandler, + mxCellState, + mxDragSource, + mxRectangle, + mxOutline, + mxClient, + mxGraphModel, + mxGeometry, + mxUndoManager, + mxKeyHandler, + mxRubberband, + mxCellRenderer, + mxRectangleShape, + mxClipboard, + mxCodec, + mxEdgeHandler, + mxGraphHandler, + mxVertexHandler, + mxCellMarker, + mxCellHighlight, + mxGraphView, +} = new mxGraphFactory(); \ No newline at end of file diff --git a/src/settings/edge.ts b/src/settings/edge.ts index ef48e02..cdd4a47 100644 --- a/src/settings/edge.ts +++ b/src/settings/edge.ts @@ -1,16 +1,15 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; -import { IMxGraph } from "../types/mxGraph"; -import { IMxPoint, IMxShape } from "../types/shapes"; + // import { registerShape } from "./Shapes"; -const { - mxEvent, - mxConstraintHandler, - mxPoint, +import { mxConstants, + mxConstraintHandler, mxEdgeHandler, + mxEvent, + mxPoint, mxRectangle, -} = mxGraphJs; +} from "../mxgraph"; +import { IMxGraph } from "../types/mxGraph"; +import { IMxPoint, IMxShape } from "../types/shapes"; const setSelectionShape = (): void => { mxEdgeHandler.prototype.createSelectionShape = function(_points: IMxPoint[]): IMxShape { diff --git a/src/settings/guide.ts b/src/settings/guide.ts index 517c314..e549710 100644 --- a/src/settings/guide.ts +++ b/src/settings/guide.ts @@ -1,10 +1,10 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { IMxGraph } from "../types/mxGraph"; -const { +import { mxConstants, mxGraphHandler, -} = mxGraphJs; +} from "../mxgraph"; +import { IMxGraph } from "../types/mxGraph"; // graph.moveCells(graph.getSelectionCells(), dx, dy); diff --git a/src/settings/init.ts b/src/settings/init.ts index ef6e397..b826d7d 100644 --- a/src/settings/init.ts +++ b/src/settings/init.ts @@ -1,22 +1,21 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; -import { IMxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; -import { initEdgeHandle } from "./edge"; -import { initPort } from "./port"; + // import { registerShape } from "./Shapes"; -const { - mxEvent, +import { + mxCellState, + mxConnectionHandler, + mxConstants, mxConstraintHandler, + mxDragSource, + mxEllipse, + mxEvent, mxGraph, mxPoint, - mxEllipse, - mxConstants, - mxConnectionHandler, - mxCellState, - mxDragSource, mxRectangle, mxUtils, -} = mxGraphJs; +} from "../mxgraph"; +import { IMxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; +import { initEdgeHandle } from "./edge"; +import { initPort } from "./port"; function initStyleSheet(graph: IMxGraph): void { const edgeStyle = graph.getStylesheet() diff --git a/src/settings/port.ts b/src/settings/port.ts index be3e144..031f41e 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -1,21 +1,21 @@ // @ts-ignore import * as mxGraphJs from "mxgraph-js"; -import { IMxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; -const { - mxGraph, +import { + mxCellHighlight, + mxCellMarker, + mxClient, mxConstants, mxEdgeHandler, - mxVertexHandler, - mxRectangle, mxEvent, - mxCellMarker, - mxCellHighlight, + mxGraph, mxGraphView, - mxClient, - mxUtils, mxPoint, -} = mxGraphJs; + mxRectangle, + mxUtils, + mxVertexHandler, +} from "../mxgraph"; +import { IMxCell, IMxGraph, IMxMouseEvent, IMxState } from "../types/mxGraph"; // tslint:disable From c039cd772c6c56904cc5ad89c0c0d8cc3c863353 Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 16:48:22 +0800 Subject: [PATCH 09/12] fix lint --- src/mxgraph.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mxgraph.ts b/src/mxgraph.ts index b59a422..9fe9f20 100644 --- a/src/mxgraph.ts +++ b/src/mxgraph.ts @@ -30,4 +30,4 @@ export const { mxCellMarker, mxCellHighlight, mxGraphView, -} = new mxGraphFactory(); \ No newline at end of file +} = new mxGraphFactory(); From 931db1d3e961147944a0cf3aea1821c1579afcc0 Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 17:08:43 +0800 Subject: [PATCH 10/12] . --- demo/src/components/FlowDetailPanel.tsx | 14 -------------- package.json | 1 - src/components/ContextMenu.tsx | 6 ------ src/components/DetailPanel.tsx | 16 ---------------- src/components/Flow.tsx | 10 +--------- src/components/Item.tsx | 7 ------- src/components/Minimap.tsx | 2 -- src/components/MxGraph.tsx | 4 ---- src/components/RegisterNode.tsx | 2 -- src/context/ClipboardContext.ts | 2 -- src/settings/Shapes.ts | 3 +-- src/settings/guide.ts | 2 -- src/settings/port.ts | 3 --- 13 files changed, 2 insertions(+), 70 deletions(-) diff --git a/demo/src/components/FlowDetailPanel.tsx b/demo/src/components/FlowDetailPanel.tsx index ecbadfb..069910f 100644 --- a/demo/src/components/FlowDetailPanel.tsx +++ b/demo/src/components/FlowDetailPanel.tsx @@ -4,10 +4,6 @@ import { EdgePanel, NodePanel, PortPanel, -<<<<<<< HEAD -======= - TextEditor, ->>>>>>> d58ba78728f17d45b6be1d0f5a481c8c5fdbe82f } from "../../../src/index"; import { @@ -18,7 +14,6 @@ export const FlowDetailPanel = () => { return ( -<<<<<<< HEAD @@ -26,15 +21,6 @@ export const FlowDetailPanel = () => { -======= - - - - - - - ->>>>>>> d58ba78728f17d45b6be1d0f5a481c8c5fdbe82f ); diff --git a/package.json b/package.json index 1050f20..2f26f86 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,6 @@ "@storybook/react": "^5.1.9", "eslint": "^6.0.1", "mxgraph": "^4.0.4", - "mxgraph-js": "^1.0.1", "office-ui-fabric-react": "^7.28.1" } } diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 1c9906d..fbcdf12 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -1,15 +1,9 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import * as React from "react"; import { mxEvent, mxUtils, -<<<<<<< HEAD } from "../mxgraph"; -======= -} = mxGraphJs; ->>>>>>> d58ba78728f17d45b6be1d0f5a481c8c5fdbe82f import { IMxGraphContext, diff --git a/src/components/DetailPanel.tsx b/src/components/DetailPanel.tsx index 7772f2d..5c4a1c0 100644 --- a/src/components/DetailPanel.tsx +++ b/src/components/DetailPanel.tsx @@ -1,11 +1,5 @@ import * as React from "react"; -// @ts-ignore -// import * as mxGraphJs from "mxgraph-js"; - -// const { -// mxEvent, -// } = mxGraphJs; import { mxEvent } from "../mxgraph"; @@ -79,18 +73,8 @@ export class DetailPanel extends React.PureComponent<{}, { cells?: IMxCell[] }> graph.getSelectionModel() .addListener(mxEvent.CHANGE, (_sender, _evt) => { - // console.log(_sender, _evt); - // console.log(graph.getSelectionCells()[0], graph.getDefaultParent()); this.setState({ cells: graph.getSelectionCells() }); - // this.forceUpdate(); }); - // const that = this; - // const selectChange = mxGraphSelectionModel.prototype.changeSelection; - // graph.getSelectionModel().changeSelection = function () { - // selectChange.apply(this, arguments); - - // console.log("change"); - // }; } private readonly _getName = (graph: IMxGraph, cells?: IMxCell[]): string => { diff --git a/src/components/Flow.tsx b/src/components/Flow.tsx index 0d31915..d3ce5b5 100644 --- a/src/components/Flow.tsx +++ b/src/components/Flow.tsx @@ -3,14 +3,6 @@ import { ICanvasData, } from "../types/flow"; -// // @ts-ignore -// import * as mxGraphJs from "mxgraph-js"; - -// const { -// mxGraph, -// } = mxGraphJs; -// import mxGraphFactory from 'mxgraph'; -// const { mxClient, mxGraphModel, mxGraph } = new mxGraphFactory(); import { mxGraph } from "../mxgraph"; import { @@ -52,7 +44,7 @@ export class Flow extends React.PureComponent { if (graph) { readData(graph, this.props.data); } - // const Background = require("../../images/grid.gif"); + return (

); diff --git a/src/components/Item.tsx b/src/components/Item.tsx index 2f1d55f..b9f4c92 100644 --- a/src/components/Item.tsx +++ b/src/components/Item.tsx @@ -1,12 +1,5 @@ import * as React from "react"; -// @ts-ignore -// import * as mxGraphJs from "mxgraph-js"; - -// const { -// mxUtils, -// } = mxGraphJs; - import { mxUtils } from "../mxgraph"; diff --git a/src/components/Minimap.tsx b/src/components/Minimap.tsx index dafe2de..2d1fa2f 100644 --- a/src/components/Minimap.tsx +++ b/src/components/Minimap.tsx @@ -1,7 +1,5 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext, diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index a5ce5ab..70b9277 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -1,8 +1,4 @@ import * as React from "react"; - -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; - import { ClipboardContext, } from "../context/ClipboardContext"; diff --git a/src/components/RegisterNode.tsx b/src/components/RegisterNode.tsx index 2b06632..838ba30 100644 --- a/src/components/RegisterNode.tsx +++ b/src/components/RegisterNode.tsx @@ -1,7 +1,5 @@ import * as React from "react"; -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import { IMxGraphContext, MxGraphContext } from "../context/MxGraphContext"; import { mxCellRenderer, diff --git a/src/context/ClipboardContext.ts b/src/context/ClipboardContext.ts index 95e1455..37bb249 100644 --- a/src/context/ClipboardContext.ts +++ b/src/context/ClipboardContext.ts @@ -1,5 +1,3 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import * as React from "react"; import { mxClipboard, diff --git a/src/settings/Shapes.ts b/src/settings/Shapes.ts index 0aaa0e3..4e9b1c6 100644 --- a/src/settings/Shapes.ts +++ b/src/settings/Shapes.ts @@ -1,5 +1,4 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; + // const { // mxCylinder, diff --git a/src/settings/guide.ts b/src/settings/guide.ts index e549710..3e3600b 100644 --- a/src/settings/guide.ts +++ b/src/settings/guide.ts @@ -1,5 +1,3 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; import { mxConstants, mxGraphHandler, diff --git a/src/settings/port.ts b/src/settings/port.ts index 031f41e..69486c4 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -1,6 +1,3 @@ -// @ts-ignore -import * as mxGraphJs from "mxgraph-js"; - import { mxCellHighlight, mxCellMarker, From e9959f388c93c7792f1d8710120a1c87dce19a0f Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 17:28:56 +0800 Subject: [PATCH 11/12] fix stroke width --- src/components/MxGraph.tsx | 2 +- src/settings/edge.ts | 3 ++- src/settings/port.ts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/MxGraph.tsx b/src/components/MxGraph.tsx index 70b9277..b493883 100644 --- a/src/components/MxGraph.tsx +++ b/src/components/MxGraph.tsx @@ -313,7 +313,7 @@ export class MxGraph extends React.PureComponent<{}, IState> { function updateNodeStyle(state: IMxState, isHover: boolean): void { state.style.strokeColor = (isHover) ? "#1976d2" : "grey"; - state.style.strokeWidth = (isHover) ? 1 : 0; + // state.style.strokeWidth = (isHover) ? 2 : 1; } function updateStyle(state: IMxState, isHover: boolean): void { diff --git a/src/settings/edge.ts b/src/settings/edge.ts index cdd4a47..c770c1b 100644 --- a/src/settings/edge.ts +++ b/src/settings/edge.ts @@ -43,12 +43,13 @@ const setSelectionShape = (): void => { this.shape.isDashed = this.isSelectionDashed(); this.shape.stroke = this.getSelectionColor(); this.shape.fill = this.getSelectionColor(); - this.shape.strokewidth = this.getSelectionStrokeWidth() / this.shape.scale / this.shape.scale; + this.shape.arrowStrokewidth = this.getSelectionStrokeWidth(); this.shape.arrowStroke = this.getSelectionColor(); this.shape.isShadow = false; console.log(this.shape); this.shape.redraw(); + console.log(this.shape.style); } if (this.parentHighlight != null) { diff --git a/src/settings/port.ts b/src/settings/port.ts index 69486c4..68c4438 100644 --- a/src/settings/port.ts +++ b/src/settings/port.ts @@ -28,6 +28,7 @@ function setPortHandler(_graph: IMxGraph): void { shape.fill = isPort ? state.style[mxConstants.STYLE_FILLCOLOR] : this.getSelectionColor(); shape.stroke = this.getSelectionColor(); + shape.strokewidth = 1 * this.graph.view.scale; shape.fillOpacity = isPort ? 100 : 20; shape.strokeOpacity = 100; From 50f727b7ef9795b07f531b0e8df540c4968d7bd5 Mon Sep 17 00:00:00 2001 From: Yongxuan Wang Date: Thu, 29 Aug 2019 17:37:35 +0800 Subject: [PATCH 12/12] fix lint --- src/settings/Shapes.ts | 54 ------------------------------------------ 1 file changed, 54 deletions(-) delete mode 100644 src/settings/Shapes.ts diff --git a/src/settings/Shapes.ts b/src/settings/Shapes.ts deleted file mode 100644 index 4e9b1c6..0000000 --- a/src/settings/Shapes.ts +++ /dev/null @@ -1,54 +0,0 @@ - - -// const { -// mxCylinder, -// mxUtils, -// mxCellRenderer, -// mxConstants, -// mxStencilRegistry, -// mxStencil -// } = mxGraphJs; - -// // tslint:disable-next-line: export-name -// export function registerShape(): void { -// // tslint:disable-next-line: function-name -// function BoxShape(): void { -// mxCylinder.call(this); -// } -// mxUtils.extend(BoxShape, mxCylinder); -// BoxShape.prototype.extrude = 10; -// BoxShape.prototype.redrawPath = function(path, x, y, w, h, isForeground) { -// var dy = this.extrude * this.scale; -// var dx = this.extrude * this.scale; - -// if (isForeground) { -// path.moveTo(0, dy); -// path.lineTo(w - dx, dy); -// path.lineTo(w, 0); -// path.moveTo(w - dx, dy); -// path.lineTo(w - dx, h); -// } else { -// path.moveTo(0, dy); -// path.lineTo(dx, 0); -// path.lineTo(w, 0); -// path.lineTo(w, h - dy); -// path.lineTo(w - dx, h); -// path.lineTo(0, h); -// path.lineTo(0, dy); -// path.lineTo(dx, 0); -// path.close(); -// } -// }; -// mxCellRenderer.registerShape('box', BoxShape); -// // -// // load from xml -// const req = mxUtils.load("../../resources/shapes.xml"); -// const root = req.getDocumentElement(); -// let shape = root.firstChild; -// while (shape) { -// if (shape.nodeType === mxConstants.NODETYPE_ELEMENT) { -// mxStencilRegistry.addStencil(shape.getAttribute("name"), new mxStencil(shape)); -// } -// shape = shape.nextSibling; -// } -// }