From 656ea3139db54b8dc9a29b8cb239d0f0df9a6c05 Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期二, 27 六月 2023 18:19:42 +0800 Subject: [PATCH] 2023-06-27 --- src/menu/components/chart/antv-X6/index.jsx | 953 ++++++++++++++++++++++++++++++----------------------------- 1 files changed, 483 insertions(+), 470 deletions(-) diff --git a/src/menu/components/chart/antv-X6/index.jsx b/src/menu/components/chart/antv-X6/index.jsx index 815cdf0..0cfcbf6 100644 --- a/src/menu/components/chart/antv-X6/index.jsx +++ b/src/menu/components/chart/antv-X6/index.jsx @@ -1,27 +1,305 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import { is, fromJS } from 'immutable' -import { Popover } from 'antd' -import { ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons' +import { Popover, Tooltip } from 'antd' +import { ToolOutlined, DeleteOutlined, FontColorsOutlined, VerticalAlignTopOutlined, VerticalAlignBottomOutlined, SaveOutlined, ZoomInOutlined, ZoomOutOutlined, OneToOneOutlined, DownloadOutlined } from '@ant-design/icons' import { Graph, Shape } from '@antv/x6' -import { Stencil } from '@antv/x6-plugin-stencil' -import { Transform } from '@antv/x6-plugin-transform' -import { Selection } from '@antv/x6-plugin-selection' -import { Snapline } from '@antv/x6-plugin-snapline' -import { Keyboard } from '@antv/x6-plugin-keyboard' -import { Clipboard } from '@antv/x6-plugin-clipboard' -import { History } from '@antv/x6-plugin-history' import MKEmitter from '@/utils/events.js' import asyncComponent from '@/utils/asyncComponent' import asyncIconComponent from '@/utils/asyncIconComponent' import { resetStyle, getTables, checkComponent } from '@/utils/utils-custom.js' +import lanes from './lane.json' +import xflows from './xflow.json' import './index.scss' const SettingComponent = asyncIconComponent(() => import('@/menu/datasource')) const ChartCompileForm = asyncIconComponent(() => import('./chartcompile')) const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent')) const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader')) + +// #region 鍒濆鍖栧浘褰� +const groups = { + top: { + position: 'top', + attrs: { + circle: { + r: 4, + magnet: true, + stroke: 'var(--mk-sys-color)', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden' + } + } + } + }, + right: { + position: 'right', + attrs: { + circle: { + r: 4, + magnet: true, + stroke: 'var(--mk-sys-color)', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden' + } + } + } + }, + bottom: { + position: 'bottom', + attrs: { + circle: { + r: 4, + magnet: true, + stroke: 'var(--mk-sys-color)', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden' + } + } + } + }, + left: { + position: 'left', + attrs: { + circle: { + r: 4, + magnet: true, + stroke: 'var(--mk-sys-color)', + strokeWidth: 1, + fill: '#fff', + style: { + visibility: 'hidden' + } + } + } + } +} + +Graph.registerNode( + 'lane', + { + inherit: 'rect', + markup: [ + { + tagName: 'rect', + selector: 'body', + }, + { + tagName: 'rect', + selector: 'name-rect', + }, + { + tagName: 'text', + selector: 'name-text', + }, + ], + attrs: { + body: { + fill: '#FFF', + stroke: '#5F95FF', + strokeWidth: 1, + }, + 'name-rect': { + width: 200, + height: 36, + fill: '#5F95FF', + stroke: '#fff', + strokeWidth: 1, + x: -1, + }, + 'name-text': { + ref: 'name-rect', + refY: 0.5, + refX: 0.5, + textAnchor: 'middle', + fontWeight: 'bold', + fill: '#fff', + fontSize: 14, + }, + }, + zIndex: 0 + }, + true, +) + +Graph.registerNode( + 'mk-rect', + { + inherit: 'rect', + width: 66, + height: 36, + attrs: { + body: { + strokeWidth: 1, + stroke: '#000000', + fill: '#FFFFFF' + }, + text: { + fontSize: 12, + fill: '#262626' + } + }, + ports: { + groups, + items: [ + { group: 'top' }, + { group: 'right' }, + { group: 'bottom' }, + { group: 'left' } + ] + } + }, + true +) + +Graph.registerNode( + 'mk-polygon', + { + inherit: 'polygon', + width: 66, + height: 36, + attrs: { + body: { + strokeWidth: 1, + stroke: '#000000', + fill: '#FFFFFF' + }, + text: { + fontSize: 12, + fill: '#262626' + } + }, + ports: { + groups, + items: [ + { group: 'top' }, + { group: 'right' }, + { group: 'bottom' }, + { group: 'left' } + ] + } + }, + true +) + +Graph.registerNode( + 'mk-circle', + { + inherit: 'circle', + width: 36, + height: 36, + attrs: { + body: { + strokeWidth: 1, + stroke: '#000000', + fill: '#FFFFFF' + }, + text: { + fontSize: 12, + fill: '#262626' + } + }, + ports: { + groups, + items: [ + { group: 'top' }, + { group: 'right' }, + { group: 'bottom' }, + { group: 'left' } + ] + } + }, + true +) + +Graph.registerNode( + 'mk-ellipse', + { + inherit: 'ellipse', + width: 66, + height: 36, + attrs: { + body: { + strokeWidth: 1, + stroke: '#000000', + fill: '#FFFFFF' + }, + text: { + fontSize: 12, + fill: '#262626' + } + }, + ports: { + groups, + items: [ + { group: 'top' }, + { group: 'right' }, + { group: 'bottom' }, + { group: 'left' } + ] + } + }, + true +) + +Graph.registerNode( + 'mk-star', + { + inherit: 'polygon', + width: 36, + height: 36, + points: '100,10 40,198 190,78 10,78 160,198', + attrs: { + body: { + fill: '#FFFFFF', + stroke: '#000000', + strokeWidth: 1, + fillRule: 'nonzero' + }, + text: { + fontSize: 12, + fill: '#262626' + } + }, + ports: { + groups, + items: [ + { group: 'top' }, + { group: 'right' }, + { group: 'bottom' }, + { group: 'left' } + ] + } + }, + true +) + +Graph.registerNode( + 'mk-text', + { + inherit: 'rect', + width: 66, + height: 36, + attrs: { + body: { + strokeWidth: 0, + fill: 'transparent' + }, + text: { + fontSize: 12, + fill: '#262626' + } + } + }, + true +) class antvX6Chart extends Component { static propTpyes = { @@ -31,8 +309,7 @@ } state = { - card: null, - eventListener: null + card: null } UNSAFE_componentWillMount () { @@ -41,9 +318,19 @@ if (card.isNew) { let _plot = { width: card.width || 24, - height: 400, + height: 500, subtype: card.subtype, - name: card.name + name: card.name, + grid: { + visible: true, + type: 'dot', + args: { + color: '#a0a0a0', + thickness: 1 + } + }, + gridType: 'dot', + export: 'png' } let _card = { @@ -95,65 +382,89 @@ }, 1000) } - viewrender = () => { - // const { card } = this.state - - // if (card.plot.subtype === 'mindmap') { - // this.ponitrender() - // } else if (card.plot.subtype === 'indentTree') { - // this.indentrender() - // } else if (card.plot.subtype === 'kapmap') { - this.kapmaprender() - // } - } - - kapmaprender = () => { + plotchange = (res) => { const { card } = this.state - // #region 鍒濆鍖栫敾甯� + if ( + card.plot.subtype !== res.plot.subtype || + (res.plot.gridType && card.plot.gridType !== res.plot.gridType) || + (res.plot.gridType && card.plot.backgroundColor !== res.plot.backgroundColor) + ) { + let _element = document.getElementById(card.uuid + 'container') + if (_element) { + _element.innerHTML = '' + } + setTimeout(() => { + this.viewrender() + }, 50) + } + + this.updateComponent(res) + } + + viewrender = () => { + const { card } = this.state + + if (card.plot.subtype === 'xflow') { + this.xflowrender() + } else if (card.plot.subtype === 'lane') { + this.lanerender() + } + } + + xflowrender = () => { + const { card } = this.state + const graph = new Graph({ container: document.getElementById(card.uuid + 'container'), - grid: true, + grid: card.plot.grid, + scaling: { + min: 0.5, + max: 2 + }, + autoResize: true, + panning: true, + background: { + color: card.plot.backgroundColor || 'transparent' + }, mousewheel: { enabled: true, zoomAtMousePosition: true, - modifiers: 'ctrl', - minScale: 0.5, - maxScale: 3, + modifiers: 'ctrl' }, connecting: { router: 'manhattan', connector: { name: 'rounded', args: { - radius: 8, - }, + radius: 8 + } }, anchor: 'center', connectionPoint: 'anchor', allowBlank: false, snap: { - radius: 20, + radius: 20 }, createEdge() { return new Shape.Edge({ attrs: { line: { - stroke: '#A2B1C3', - strokeWidth: 2, + stroke: '#000000', + strokeWidth: 1, targetMarker: { name: 'block', width: 12, - height: 8, - }, - }, + height: 8 + } + } }, - zIndex: 0, + zIndex: 0 }) }, validateConnection({ targetMagnet }) { return !!targetMagnet - }, + } }, highlighting: { magnetAdsorbed: { @@ -161,442 +472,118 @@ args: { attrs: { fill: '#5F95FF', - stroke: '#5F95FF', + stroke: '#5F95FF' + } + } + } + } + }) + + let cells = [] + xflows.forEach((item) => { + if (item.shape === 'edge') { + cells.push(graph.createEdge(item)) + } else { + cells.push(graph.createNode(item)) + } + }) + graph.resetCells(cells) + graph.positionContent('center') + } + + lanerender = () => { + const { card } = this.state + + const graph = new Graph({ + container: document.getElementById(card.uuid + 'container'), + scaling: { + min: 0.5, + max: 2 + }, + autoResize: true, + panning: true, + background: { color: '#ffffff' }, + mousewheel: { + enabled: true, + zoomAtMousePosition: true, + modifiers: 'ctrl' + }, + connecting: { + router: 'manhattan', + connector: { + name: 'rounded', + args: { + radius: 8 + } + }, + anchor: 'center', + connectionPoint: 'anchor', + allowBlank: false, + snap: { + radius: 20 + }, + createEdge() { + return new Shape.Edge({ + attrs: { + line: { + stroke: '#000000', + strokeWidth: 1, + targetMarker: { + name: 'block', + width: 12, + height: 8 + } + } }, - }, + zIndex: 2 + }) }, + validateConnection({ targetMagnet }) { + return !!targetMagnet + } }, - }) - // #endregion - - // #region 浣跨敤鎻掍欢 - graph - .use( - new Transform({ - resizing: true, - rotating: true, - }), - ) - .use( - new Selection({ - rubberband: true, - showNodeSelectionBox: true, - }), - ) - .use(new Snapline()) - .use(new Keyboard()) - .use(new Clipboard()) - .use(new History()) - // #endregion - - // #region 鍒濆鍖� stencil - const stencil = new Stencil({ - title: '娴佺▼鍥�', - target: graph, - stencilGraphWidth: 200, - stencilGraphHeight: 180, - // collapsable: true, - groups: [ - { - title: '閫氱敤鑺傜偣', - name: 'group1', - }, - { - title: '绯荤粺璁捐鍥�', - name: 'group2', - graphHeight: 250, - layoutOptions: { - rowHeight: 70, - }, - }, - ], - layoutOptions: { - columns: 2, - columnWidth: 80, - rowHeight: 55, + highlighting: { + magnetAdsorbed: { + name: 'stroke', + args: { + attrs: { + fill: '#5F95FF', + stroke: '#5F95FF' + } + } + } }, - }) - document.getElementById(card.uuid + 'stencil').appendChild(stencil.container) - // #endregion + translating: { + restrict(cellView) { + const cell = cellView.cell + const parentId = cell.prop('parent') - // #region 蹇嵎閿笌浜嬩欢 - graph.bindKey(['meta+c', 'ctrl+c'], () => { - const cells = graph.getSelectedCells() - if (cells.length) { - graph.copy(cells) - } - return false - }) - graph.bindKey(['meta+x', 'ctrl+x'], () => { - const cells = graph.getSelectedCells() - if (cells.length) { - graph.cut(cells) - } - return false - }) - graph.bindKey(['meta+v', 'ctrl+v'], () => { - if (!graph.isClipboardEmpty()) { - const cells = graph.paste({ offset: 32 }) - graph.cleanSelection() - graph.select(cells) - } - return false - }) - - // undo redo - graph.bindKey(['meta+z', 'ctrl+z'], () => { - if (graph.canUndo()) { - graph.undo() - } - return false - }) - graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => { - if (graph.canRedo()) { - graph.redo() - } - return false - }) - - // select all - graph.bindKey(['meta+a', 'ctrl+a'], () => { - const nodes = graph.getNodes() - if (nodes) { - graph.select(nodes) + if (parentId) { + const parentNode = graph.getCellById(parentId) + if (parentNode) { + return parentNode.getBBox().moveAndExpand({ + x: 0, + y: 36, + width: 0, + height: -36, + }) + } + } + return cell.getBBox() + } } }) - // delete - graph.bindKey('backspace', () => { - const cells = graph.getSelectedCells() - if (cells.length) { - graph.removeCells(cells) + let cells = [] + lanes.forEach((item) => { + if (item.shape === 'edge') { + cells.push(graph.createEdge(item)) + } else { + cells.push(graph.createNode(item)) } }) - - // zoom - graph.bindKey(['ctrl+1', 'meta+1'], () => { - const zoom = graph.zoom() - if (zoom < 1.5) { - graph.zoom(0.1) - } - }) - graph.bindKey(['ctrl+2', 'meta+2'], () => { - const zoom = graph.zoom() - if (zoom > 0.5) { - graph.zoom(-0.1) - } - }) - - // 鎺у埗杩炴帴妗╂樉绀�/闅愯棌 - const showPorts = (ports, show) => { - for (let i = 0, len = ports.length; i < len; i += 1) { - ports[i].style.visibility = show ? 'visible' : 'hidden' - } - } - graph.on('node:mouseenter', () => { - const container = document.getElementById(card.uuid + 'container') - const ports = container.querySelectorAll('.x6-port-body') - showPorts(ports, true) - }) - graph.on('node:mouseleave', () => { - const container = document.getElementById(card.uuid + 'container') - const ports = container.querySelectorAll('.x6-port-body') - showPorts(ports, false) - }) - // #endregion - - // #region 鍒濆鍖栧浘褰� - const ports = { - groups: { - top: { - position: 'top', - attrs: { - circle: { - r: 4, - magnet: true, - stroke: '#5F95FF', - strokeWidth: 1, - fill: '#fff', - style: { - visibility: 'hidden', - }, - }, - }, - }, - right: { - position: 'right', - attrs: { - circle: { - r: 4, - magnet: true, - stroke: '#5F95FF', - strokeWidth: 1, - fill: '#fff', - style: { - visibility: 'hidden', - }, - }, - }, - }, - bottom: { - position: 'bottom', - attrs: { - circle: { - r: 4, - magnet: true, - stroke: '#5F95FF', - strokeWidth: 1, - fill: '#fff', - style: { - visibility: 'hidden', - }, - }, - }, - }, - left: { - position: 'left', - attrs: { - circle: { - r: 4, - magnet: true, - stroke: '#5F95FF', - strokeWidth: 1, - fill: '#fff', - style: { - visibility: 'hidden', - }, - }, - }, - }, - }, - items: [ - { - group: 'top', - }, - { - group: 'right', - }, - { - group: 'bottom', - }, - { - group: 'left', - }, - ], - } - - Graph.registerNode( - 'custom-rect', - { - inherit: 'rect', - width: 66, - height: 36, - attrs: { - body: { - strokeWidth: 1, - stroke: '#5F95FF', - fill: '#EFF4FF', - }, - text: { - fontSize: 12, - fill: '#262626', - }, - }, - ports: { ...ports }, - }, - true, - ) - - Graph.registerNode( - 'custom-polygon', - { - inherit: 'polygon', - width: 66, - height: 36, - attrs: { - body: { - strokeWidth: 1, - stroke: '#5F95FF', - fill: '#EFF4FF', - }, - text: { - fontSize: 12, - fill: '#262626', - }, - }, - ports: { - ...ports, - items: [ - { - group: 'top', - }, - { - group: 'bottom', - }, - ], - }, - }, - true, - ) - - Graph.registerNode( - 'custom-circle', - { - inherit: 'circle', - width: 45, - height: 45, - attrs: { - body: { - strokeWidth: 1, - stroke: '#5F95FF', - fill: '#EFF4FF', - }, - text: { - fontSize: 12, - fill: '#262626', - }, - }, - ports: { ...ports }, - }, - true, - ) - - Graph.registerNode( - 'custom-image', - { - inherit: 'rect', - width: 52, - height: 52, - markup: [ - { - tagName: 'rect', - selector: 'body', - }, - { - tagName: 'image', - }, - { - tagName: 'text', - selector: 'label', - }, - ], - attrs: { - body: { - stroke: '#5F95FF', - fill: '#5F95FF', - }, - image: { - width: 26, - height: 26, - refX: 13, - refY: 16, - }, - label: { - refX: 3, - refY: 2, - textAnchor: 'left', - textVerticalAnchor: 'top', - fontSize: 12, - fill: '#fff', - }, - }, - ports: { ...ports }, - }, - true, - ) - - const r1 = graph.createNode({ - shape: 'custom-rect', - label: '寮�濮�', - attrs: { - body: { - rx: 20, - ry: 26, - }, - }, - }) - const r2 = graph.createNode({ - shape: 'custom-rect', - label: '杩囩▼', - }) - const r3 = graph.createNode({ - shape: 'custom-rect', - attrs: { - body: { - rx: 6, - ry: 6, - }, - }, - label: '鍙�夎繃绋�', - }) - const r4 = graph.createNode({ - shape: 'custom-polygon', - attrs: { - body: { - refPoints: '0,10 10,0 20,10 10,20', - }, - }, - label: '鍐崇瓥', - }) - const r5 = graph.createNode({ - shape: 'custom-polygon', - attrs: { - body: { - refPoints: '10,0 40,0 30,20 0,20', - }, - }, - label: '鏁版嵁', - }) - const r6 = graph.createNode({ - shape: 'custom-circle', - label: '杩炴帴', - }) - stencil.load([r1, r2, r3, r4, r5, r6], 'group1') - - const imageShapes = [ - { - label: 'Client', - image: - 'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg', - }, - { - label: 'Http', - image: - 'https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg', - }, - { - label: 'Api', - image: - 'https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg', - }, - { - label: 'Sql', - image: - 'https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg', - }, - { - label: 'Clound', - image: - 'https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg', - }, - { - label: 'Mq', - image: - 'https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg', - }, - ] - const imageNodes = imageShapes.map((item) => - graph.createNode({ - shape: 'custom-image', - label: item.label, - attrs: { - image: { - 'xlink:href': item.image, - }, - }, - }), - ) - stencil.load(imageNodes, 'group2') + graph.resetCells(cells) + graph.positionContent('top') } updateComponent = (card) => { @@ -646,10 +633,10 @@ let _style = resetStyle(card.style) return ( - <div className="menu-scatter-chart-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}> + <div className="menu-x6-chart-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}> <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ <div className="mk-popover-control"> - <ChartCompileForm config={card} plotchange={this.updateComponent}/> + <ChartCompileForm config={card} plotchange={this.plotchange}/> <CopyComponent type="antvG6" card={card}/> <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/> <DeleteOutlined className="close" title="delete" onClick={() => this.props.deletecomponent(card.uuid)}/> @@ -659,8 +646,34 @@ <ToolOutlined/> </Popover> <NormalHeader config={card} updateComponent={this.updateComponent}/> + <div className="mk-toolbar"> + <div className="left-tool"> + {card.plot.subtype === 'xflow' ? <Tooltip title="缃墠"> + <VerticalAlignTopOutlined/> + </Tooltip> : null} + {card.plot.subtype === 'xflow' ? <Tooltip title="缃悗"> + <VerticalAlignBottomOutlined/> + </Tooltip> : null} + <Tooltip title="淇濆瓨"> + <SaveOutlined/> + </Tooltip> + {card.plot.export === 'png' ? <Tooltip title="瀵煎嚭鍥剧墖"> + <DownloadOutlined/> + </Tooltip> : null} + </div> + <div className="right-tool"> + <Tooltip title="鏀惧ぇ"> + <ZoomInOutlined/> + </Tooltip> + <Tooltip title="缂╁皬"> + <ZoomOutOutlined/> + </Tooltip> + <Tooltip title="1:1"> + <OneToOneOutlined/> + </Tooltip> + </div> + </div> <div className="canvas" style={{width: '100%', minHeight: card.plot.height, height: card.plot.height}} id={card.uuid + 'canvas'}> - <div id={card.uuid + 'stencil'} className="mk-stencil"></div> <div id={card.uuid + 'container'} className="mk-container"></div> </div> <div className="component-name"> -- Gitblit v1.8.0