diff --git a/package-lock.json b/package-lock.json index c38ddc0..e8042d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,21 @@ { "name": "@vesoft-inc/veditor", - "version": "4.3.3-beta.4", + "version": "4.4.6-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@vesoft-inc/veditor", - "version": "4.3.3-beta.4", + "version": "4.4.6-beta.0", "license": "ISC", "dependencies": { "canvg": "^4.0.0", "dagre": "^0.8.4", "gl-matrix": "^3.4.3", + "url-loader": "^4.1.1", "uuid": "^8.3.2" }, "devDependencies": { - "url-loader": "^4.1.1", "@types/react": "^18.0.17", "antd": "^3.22.0", "babel-loader": "^8.0.2", @@ -10826,4 +10826,4 @@ "dev": true } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index e84ecd8..34e1259 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vesoft-inc/veditor", - "version": "4.4.5", + "version": "4.4.7-beta.9", "description": "svg flow editor", "main": "./dist/VEditor.js", "types": "./types/index.d.ts", diff --git a/src/Shape/Line.ts b/src/Shape/Line.ts index aad3d15..7d54b18 100644 --- a/src/Shape/Line.ts +++ b/src/Shape/Line.ts @@ -20,6 +20,7 @@ export interface InstanceLine extends AnyMap { to: InstanceNodePoint; pathData: Path; shadowPath?: SVGPathElement; + width?: number; bezierData?: { from: Position; startControlPoint: Position; @@ -222,9 +223,9 @@ class Line { } else { line = this.lines[data.uuid]; } + if (!line) return; //这里有可能被删除node时的关联删除线了 let uuid = line.data.uuid; const { nodes } = this.node; - if (!line) return; //这里有可能被删除node时的关联删除线了 delete this.lines[uuid]; // 删除关联线 const { from, to } = line.data; @@ -323,8 +324,8 @@ class Line { /** * 注册线 */ - registeLine(type: string, data: LineRender) { - this.shapes[type] = Object.assign({}, this.shapes["default"], data); + registeLine(type: string, data: LineRender,extend="default") { + this.shapes[type] = Object.assign({}, this.shapes[extend], data); } /** diff --git a/src/Shape/Lines/Line.ts b/src/Shape/Lines/Line.ts index 7d11a0c..a30eb3d 100644 --- a/src/Shape/Lines/Line.ts +++ b/src/Shape/Lines/Line.ts @@ -9,13 +9,14 @@ import { Path } from "../../Utils"; import { AnyMap } from "../../Utils/types"; import { VEditorLine } from "../../Model/Schema"; import VEditor from "../../VEditor"; +import { Utils } from '../..'; export interface LineRender extends AnyMap { graph?: Graph; adsorb?: [number, number]; //磁吸的范围 render?: (instanceLine: InstanceLine) => SVGElement; - renderArrow?: (instanceLine?: InstanceLine) => SVGElement; - renderArrow2?: (instanceLine?: InstanceLine) => SVGElement; + renderArrow?: (instanceLine: InstanceLine) => SVGElement; + renderArrow2?: (instanceLine: InstanceLine) => SVGElement; renderLabel?: (instanceLine?: InstanceLine) => SVGElement; checkNewLine?: (lineData: VEditorLine, editor: VEditor) => boolean; } @@ -35,6 +36,8 @@ const DefaultLine: LineRender = { adsorb: [20, 20], startSpace: 8, endSpace: 8, + startGap: 0, + endGap: 0, render(line: InstanceLine) { const { from, to, data } = line; const pathString = this.makePath(from, to, line); @@ -47,7 +50,7 @@ const DefaultLine: LineRender = { setAttrs(path, { d: pathString, class: "ve-line-path", - "stroke-dasharray": "10", + "stroke-dasharray": data.width||"10", fill: "none", "stroke-width": 2, "pointer-events": "visiblepainted", @@ -81,19 +84,25 @@ const DefaultLine: LineRender = { from: InstanceNodePoint, to: InstanceNodePoint, line: InstanceLine - ):string { + ): string { + from = { ...from }; + to = { ...to }; const start = { x: from.x, y: from.y, }; const end = { x: to.x, y: to.y, } let startControlPoint = { x: start.x, y: start.y }; let endControlPoint = { x: end.x, y: end.y }; - const startSpace = this.startSpace; // 顶部距离node节点的距离 - const endSpace = this.endSpace; // 底部距离node节点的距离 const startAngle = this.getPointAngle(from); const endAngle = this.getPointAngle(to); - start.x += startSpace * Math.cos(startAngle); - start.y += startSpace * Math.sin(startAngle); - end.x += endSpace * Math.cos(endAngle); - end.y += endSpace * Math.sin(endAngle); + from.x += this.startGap * Math.cos(startAngle); + from.y += this.startGap * Math.sin(startAngle); + to.x += this.endGap * Math.cos(endAngle); + to.y += this.endGap * Math.sin(endAngle); + + start.x += (this.startSpace+this.startGap) * Math.cos(startAngle); + start.y += (this.startSpace+this.startGap) * Math.sin(startAngle); + end.x += (this.endSpace+this.endGap) * Math.cos(endAngle); + end.y += (this.endSpace + this.endGap) * Math.sin(endAngle); + let path = ''; const pathString = `M${from.x} ${from.y} T ${start.x} ${start.y}`; const toPointString = `${end.x} ${end.y} T ${to.x} ${to.y} `; @@ -176,9 +185,16 @@ const DefaultLine: LineRender = { }, renderArrow(line: InstanceLine) { - const { to } = line; + if (!line) { + return Utils.SVGHelper.path(); + } + const { to,data } = line; const angle = this.getPointAngle(to); - const pathString = `M${0} ${0}L${10} ${5}L${10} ${-5}Z`; + const width = (data.data?.arrowWidth as number) || 10; + const height = (data.data?.arrowHeight as number) || 10; + const pathString = `M${0} ${0}L${height} ${width / 2}L${height} ${ + -width / 2 + }Z`; const path = line.arrow ? line.arrow : SVGHelper.path(); // 进行角度的中心变换 const matrix = mat2d.create(); @@ -187,7 +203,7 @@ const DefaultLine: LineRender = { setAttrs(path, { class: "ve-line-arrow", d: pathString, - fill: "rgba(178,190,205,0.7)", + fill: data.data?.arrowColor||"rgba(178,190,205,0.7)", transform: `matrix(${matrix.join(",")})`, ...(line.data.arrowStyle as AnyMap), }); @@ -246,9 +262,8 @@ const DefaultLine: LineRender = { setAttrs(text, { text: label || "", fill: style.fill, - fontSize: style.fontSize, - textAnchor: "middle", - dominantBaseline: "middle", + "dominant-baseline": "middle", + "alignment-baseline": "after-edge", x, y, }); @@ -264,12 +279,14 @@ const DefaultLine: LineRender = { height, stroke: "transparent", x: x - width * 0.5, - y: y - height * 0.5, + y: y - height-1, }); setAttrs(labelGroup, { class: "ve-line-label", "data-label": encodeURI(totalLabel), }); + //fix text vertical middle + labelGroup.style.transform = `translate(0px,${height/2}px)`; if (autoRotate) { // 文字顺序方向 let angle = SVGHelper.getAngle(from, to); diff --git a/src/Shape/Lines/PolyLine.ts b/src/Shape/Lines/PolyLine.ts index 206c03e..2f80f5a 100644 --- a/src/Shape/Lines/PolyLine.ts +++ b/src/Shape/Lines/PolyLine.ts @@ -19,14 +19,12 @@ const PolyLine: LineRender = { ) { const start = { x: from.x, y: from.y, }; const end = { x: to.x, y: to.y, } - const startSpace = this.startSpace; // 顶部距离node节点的距离 - const endSpace = this.endSpace; // 底部距离node节点的距离 const startAngle = this.getPointAngle(from); const endAngle = this.getPointAngle(to); - start.x += startSpace * Math.cos(startAngle); - start.y += startSpace * Math.sin(startAngle); - end.x += endSpace * Math.cos(endAngle); - end.y += endSpace * Math.sin(endAngle); + start.x += this.startGap * Math.cos(startAngle); + start.y += this.startGap * Math.sin(startAngle); + end.x += this.endGap * Math.cos(endAngle); + end.y += this.endGap * Math.sin(endAngle); const disX = Math.abs(end.x - start.x); const disY = Math.abs(end.y - start.y); const lineDistanceY = this.lineDistance || (disY * .5); diff --git a/src/Utils/dom.ts b/src/Utils/dom.ts index 1e37da8..ed1987a 100644 --- a/src/Utils/dom.ts +++ b/src/Utils/dom.ts @@ -1,14 +1,14 @@ import BezierLine from "./BezierLine"; import { Position } from "./types"; -export function getDOMRect(str, callback) { +export function getDOMRect(str) { const div = document.createElement("div"); div.style.position = "fixed"; div.style.visibility = "hidden"; div.innerHTML = str; document.body.appendChild(div); const rect = div.getBoundingClientRect(); - // document.body.removeChild(div); + document.body.removeChild(div); return rect; } export function svgWrapper(svgString: string, parent?: SVGElement): SVGElement { diff --git a/src/index.less b/src/index.less index 52629e3..d234515 100644 --- a/src/index.less +++ b/src/index.less @@ -1,183 +1,220 @@ @keyframes dashing { - from { - stroke-dashoffset: 200; - } - to { - stroke-dashoffset: 0; - } + from { + stroke-dashoffset: 200; + } + + to { + stroke-dashoffset: 0; + } } + .ve-editor { - width: 100%; - height: 100%; - position: relative; - .ve-editor-back{ - width:100%; - height:100%; - position: absolute; - z-index: 0; - left:0; - top:0; - } - .ve-minimap{ - position: absolute; - top:10px; - right:10px; - background:#fff; - border:1px solid #cecece; - border-radius:5px; - overflow: hidden; - width: 160px; - height: 127px; - .drag-rect{ - position: absolute; - left:0px; - box-sizing: content-box; - top:0px; - border:2px solid #08c; - cursor: pointer; - transition: all 200ms ease; - } - .drag-point{ - width:10px; - height: 10px; - border-radius: 5px; - border:2px solid #08c; - background: #fff; - position: absolute; - right:-5px; - bottom:-5px; - cursor: nwse-resize; - } - } - > .ve-editor-svg { - cursor: grab; - width: 100%; - height: 100%; - position: absolute; - svg { - position: absolute; - left: 0; - top: 0; - outline: none; - } - .ve-node { - &:hover,&.active { - .ve-link-points{ + width: 100%; + height: 100%; + position: relative; + + .ve-editor-back { + width: 100%; + height: 100%; + position: absolute; + z-index: 0; + left: 0; + top: 0; + } + + .ve-minimap { + position: absolute; + top: 10px; + right: 10px; + background: #fff; + border: 1px solid #cecece; + border-radius: 5px; + overflow: hidden; + width: 160px; + height: 127px; + + .drag-rect { + position: absolute; + left: 0px; + box-sizing: content-box; + top: 0px; + border: 2px solid #08c; + cursor: pointer; + transition: all 200ms ease; + } + + .drag-point { + width: 10px; + height: 10px; + border-radius: 5px; + border: 2px solid #08c; + background: #fff; + position: absolute; + right: -5px; + bottom: -5px; + cursor: nwse-resize; + } + } + + >.ve-editor-svg { + cursor: grab; + width: 100%; + height: 100%; + position: absolute; + + svg { + position: absolute; + left: 0; + top: 0; + outline: none; + } + + .ve-node { + .ve-node-shape:focus { + outline: none; + } + + &:hover, + &.active { + .ve-link-points { display: block; } } + .ve-link-points { - cursor:crosshair; + cursor: crosshair; display: none; - &:hover,&.hover { - fill: #4c79ff; - cursor: crosshair; - display: block; - } - } - &.active{ + + &:hover, + &.hover { + fill: #4c79ff; + cursor: crosshair; + display: block; + } + } + + &.active { .icon-node { - transition: stroke 400ms; - stroke: rgba(76, 121, 255, 1); - } + transition: stroke 400ms; + stroke: rgba(76, 121, 255, 1); + } + } + + .ve-node-shape { + cursor: move; + + &:hover { + >.icon-node { + stroke: #4c79ff; + // fill-opacity: 0.2!important; + } + } + + &.success { + .icon-node { + stroke: green; + fill: #fff; + } + } + + &.error { + .icon-node { + stroke: red; + } + } + + &.running { + .icon-node { + stroke: #4c79ff; + } + } + } + } + + .ve-line { + .ve-line-path { + transition: stroke-dasharray 300ms ease-out; } - .ve-node-shape { - cursor: move; - &:hover { - > .icon-node { - stroke: #4c79ff; - // fill-opacity: 0.2!important; - } - } - &.success { - .icon-node { - stroke: green; - fill: #fff; - } - } - &.error { - .icon-node { - stroke: red; - } - } - &.running { - .icon-node { - stroke: #4c79ff; - } - } - } - } - - .ve-line { - .ve-line-path{ - transition: stroke-dasharray 300ms ease-out; - } - .ve-shdow-path{ - stroke: transparent; - stroke-width: 5px; - fill:none; - } - &:hover { - .ve-line-shape { - opacity: 0.5; - } - .ve-line-arrow { - opacity: 0.5; - } - } - &.active{ - .ve-line-arrow{ + + .ve-shdow-path { + stroke: transparent; + stroke-width: 5px; + fill: none; + } + + &:hover { + .ve-line-shape { + opacity: 0.5; + } + + .ve-line-arrow { + opacity: 0.5; + } + } + + &.active { + .ve-line-arrow { stroke: #4c79ff; } - path{ + + path { stroke: #4c79ff; } } - &.running { - .ve-line-path{ - stroke-dasharray: 5 !important; - animation: dashing 5s linear infinite; - } - } - .ve-line-shape { - - cursor: pointer; - } - .ve-line-arrow { - cursor: crosshair; - } - .ve-line-label{ - text{ - text-anchor: middle; - } - } - } - .anchor-line{ - stroke: #4c79ff; - } - .ve-paper-lineing{ - .ve-link-points{ - display: block; + + &.running { + .ve-line-path { + stroke-dasharray: 5 !important; + animation: dashing 5s linear infinite; + } + } + + .ve-line-shape { + + cursor: pointer; + } + + .ve-line-arrow { + cursor: crosshair; + } + + .ve-line-label { + text { + text-anchor: middle; } + } + } + + .anchor-line { + stroke: #4c79ff; + } + + .ve-paper-lineing { + .ve-link-points { + display: block; + } } - } - > .ve-editor-html { - width: 100%; - height: 100%; - position: absolute; - } - .anchor-back{ - position: absolute; - top:0; - left:0; - } + } + + >.ve-editor-html { + width: 100%; + height: 100%; + position: absolute; + } + + .anchor-back { + position: absolute; + top: 0; + left: 0; + } } -.ve-node-wrapper{ - border:1px solid #08c; - border-radius: 8px; - box-sizing: border-box; - display: flex; - justify-content: center; - background-color: #fff; - align-items: center; + +.ve-node-wrapper { + border: 1px solid #08c; + border-radius: 8px; + box-sizing: border-box; + display: flex; + justify-content: center; + background-color: #fff; + align-items: center; } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 368f882..1e2d107 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "emitDecoratorMetadata": true, "jsx": "react", "outDir": "dist", - "module": "esnext", + "module": "NodeNext", "target": "ES2015", "resolveJsonModule": true, "moduleResolution": "NodeNext"