Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support strokeStyle for mind node and link #974 #975

Merged
merged 1 commit into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/polite-ants-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@plait/mind': minor
---

support strokeStyle for mind node and link

BREAK CHANGES:

1. It is planned to replace branchColor and branchWidth with strokeColor and strokeWidth. To maintain compatibility, branchColor and branchWidth will not be deleted. BranchColor and branchWidth will be applied first.
2. Both branchWidth and branchColor attributes are applied to the child node first and no longer rely on the attributes of the parent node. BranchShape remains dependent on the attributes of the parent node.


破坏性更改:

1. 计划用 strokeColor 和 strokeWidth 替换 branchColor 和 branchWidth,为保持兼容 branchColor 和 branchWidth 不删除,优先应用 branchColor 和 branchWidth。
2. branchWidth 和 branchColor 属性都优先应用 child 节点,不再依赖父节点的属性,branchShape 保持依赖父节点属性
1 change: 1 addition & 0 deletions packages/common/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './default';
export * from './media';
export * from './resize';
export * from './property';
5 changes: 5 additions & 0 deletions packages/common/src/constants/property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum StrokeStyle {
solid = 'solid',
dashed = 'dashed',
dotted = 'dotted'
}
1 change: 1 addition & 0 deletions packages/common/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './drawing';
export * from './rotate';
export * from './elements';
export * from './animate';
export * from './stroke';
12 changes: 12 additions & 0 deletions packages/common/src/utils/stroke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { StrokeStyle } from '../constants';

export const getStrokeLineDash = (strokeStyle: StrokeStyle, strokeWidth: number) => {
switch (strokeStyle) {
case StrokeStyle.dashed:
return [8, 8 + strokeWidth];
case StrokeStyle.dotted:
return [2, 4 + strokeWidth];
default:
return undefined;
}
};
1 change: 0 additions & 1 deletion packages/core/src/utils/drawing/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export function drawLinearPath(points: Point[], options?: Options, closePath?: b
path.setAttribute('fill', `${options?.fill || 'none'}`);
options?.strokeLineDash && path.setAttribute('stroke-dasharray', `${options.strokeLineDash}`);
g.appendChild(path);

return g;
}

Expand Down
9 changes: 5 additions & 4 deletions packages/draw/src/generators/geometry-shape.generator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BasicShapes, PlaitGeometry } from '../interfaces';
import { Generator } from '@plait/common';
import { getFillByElement, getLineDashByElement, getStrokeColorByElement } from '../utils/style/stroke';
import { Generator, getStrokeLineDash } from '@plait/common';
import { getFillByElement, getStrokeColorByElement, getStrokeStyleByElement } from '../utils/style/stroke';
import { drawGeometry, getStrokeWidthByElement } from '../utils';
import { RectangleClient } from '@plait/core';

Expand All @@ -17,10 +17,11 @@ export class GeometryShapeGenerator extends Generator<PlaitGeometry, ShapeData>
if (shape === BasicShapes.text) {
return;
}
const fill = getFillByElement(this.board, element);
const strokeWidth = getStrokeWidthByElement(element);
const strokeColor = getStrokeColorByElement(this.board, element);
const fill = getFillByElement(this.board, element);
const strokeLineDash = getLineDashByElement(element);
const strokeStyle = getStrokeStyleByElement(this.board, element);
const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
return drawGeometry(this.board, RectangleClient.inflate(rectangle, -strokeWidth), shape, {
stroke: strokeColor,
strokeWidth,
Expand Down
9 changes: 5 additions & 4 deletions packages/draw/src/generators/table.generator.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { TableSymbols } from '../interfaces';
import { Generator } from '@plait/common';
import { Generator, getStrokeLineDash } from '@plait/common';
import { PlaitElement, RectangleClient } from '@plait/core';
import { PlaitBaseTable } from '../interfaces/table';
import { getEngine } from '../engines';
import { getDrawDefaultStrokeColor, getFillByElement, getLineDashByElement, getStrokeColorByElement, getStrokeWidthByElement } from '../utils';
import { getStrokeColorByElement, getStrokeStyleByElement, getStrokeWidthByElement } from '../utils';

export interface TableData {}

Expand All @@ -14,16 +14,17 @@ export class TableGenerator<T extends PlaitElement = PlaitBaseTable> extends Gen

draw(element: T, data: TableData) {
const rectangle = RectangleClient.getRectangleByPoints(element.points!);
const strokeLineDash = getLineDashByElement(element);
const strokeWidth = getStrokeWidthByElement(element);
const strokeColor = getStrokeColorByElement(this.board, element);
const strokeStyle = getStrokeStyleByElement(this.board, element);
const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
return getEngine(TableSymbols.table).draw(
this.board,
rectangle,
{
strokeWidth,
stroke: strokeColor,
strokeLineDash,
strokeLineDash
},
{
element: element
Expand Down
7 changes: 4 additions & 3 deletions packages/draw/src/utils/arrow-line/arrow-line-basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
setStrokeLinecap
} from '@plait/core';
import { pointsOnBezierCurves } from 'points-on-curve';
import { getPointOnPolyline, getPointByVectorComponent, removeDuplicatePoints, getExtendPoint } from '@plait/common';
import { getPointOnPolyline, getPointByVectorComponent, removeDuplicatePoints, getExtendPoint, getStrokeLineDash } from '@plait/common';
import {
ArrowLineHandle,
ArrowLineMarkerType,
Expand All @@ -25,7 +25,7 @@ import {
PlaitShapeElement,
StrokeStyle
} from '../../interfaces';
import { getLineDashByElement, getStrokeColorByElement } from '../style/stroke';
import { getStrokeColorByElement, getStrokeStyleByElement } from '../style/stroke';
import { getEngine } from '../../engines';
import { getElementShape } from '../shape';
import { DefaultLineStyle, LINE_TEXT_SPACE } from '../../constants/line';
Expand Down Expand Up @@ -115,7 +115,8 @@ export const getCurvePoints = (board: PlaitBoard, element: PlaitArrowLine) => {
export const drawArrowLine = (board: PlaitBoard, element: PlaitArrowLine) => {
const strokeWidth = getStrokeWidthByElement(element);
const strokeColor = getStrokeColorByElement(board, element);
const strokeLineDash = getLineDashByElement(element);
const strokeStyle = getStrokeStyleByElement(board, element);
const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
const options = { stroke: strokeColor, strokeWidth, strokeLineDash };
const lineG = createG();
let points = getArrowLinePoints(board, element);
Expand Down
13 changes: 1 addition & 12 deletions packages/draw/src/utils/style/stroke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@ export const getFillByElement = (board: PlaitBoard, element: PlaitElement) => {
return fill;
};

export const getLineDashByElement = (element: PlaitElement) => {
switch (element.strokeStyle) {
case StrokeStyle.dashed:
return [8, 8 + getStrokeWidthByElement(element)];
case StrokeStyle.dotted:
return [2, 4 + getStrokeWidthByElement(element)];
default:
return undefined;
}
};

export const getStrokeStyleByElement = (element: PlaitElement) => {
export const getStrokeStyleByElement = (board: PlaitBoard, element: PlaitElement) => {
return element.strokeStyle || StrokeStyle.solid;
};
7 changes: 4 additions & 3 deletions packages/draw/src/utils/vector-line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { getLineMemorizedLatest } from './memorize';
import { DefaultLineStyle } from '../constants/line';
import { alignPoints } from './arrow-line';
import { getStrokeWidthByElement } from './common';
import { getFillByElement, getLineDashByElement, getStrokeColorByElement } from './style';
import { getFillByElement, getStrokeColorByElement, getStrokeStyleByElement } from './style';
import { VectorLineShapeGenerator } from '../generators/vector-line-generator';
import { pointsOnBezierCurves } from 'points-on-curve';
import { removeDuplicatePoints } from '@plait/common';
import { getStrokeLineDash } from '@plait/common';

export const isClosedVectorLine = (vectorLine: PlaitVectorLine) => {
const points = vectorLine.points;
Expand Down Expand Up @@ -74,7 +74,8 @@ export const vectorLineCreating = (
export const drawVectorLine = (board: PlaitBoard, element: PlaitVectorLine) => {
const strokeWidth = getStrokeWidthByElement(element);
const strokeColor = getStrokeColorByElement(board, element);
const strokeLineDash = getLineDashByElement(element);
const strokeStyle = getStrokeStyleByElement(board, element);
const strokeLineDash = getStrokeLineDash(strokeStyle, strokeWidth);
const fill = getFillByElement(board, element);
const options = { stroke: strokeColor, strokeWidth, strokeLineDash, fill };
const lineG = createG();
Expand Down
1 change: 0 additions & 1 deletion packages/mind/src/constants/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export const BASE = 4;
export const PRIMARY_COLOR = '#6698FF';
export const GRAY_COLOR = '#AAAAAA';
export const STROKE_WIDTH = 3;
export const BRANCH_WIDTH = 3;

export const EXTEND_OFFSET = 8;
export const EXTEND_DIAMETER = 16;
Expand Down
3 changes: 2 additions & 1 deletion packages/mind/src/interfaces/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isNullOrUndefined, NODE_TO_PARENT, Path, PlaitBoard, PlaitElement, Plai
import { MindQueries } from '../queries';
import { ELEMENT_TO_NODE } from '../utils';
import { BaseData, EmojiData, ImageData } from './element-data';
import { MindNodeComponent } from '../mind-node.component';
import { StrokeStyle } from '@plait/common';

export interface MindElement<T = BaseData> extends PlaitElement {
data: T;
Expand All @@ -18,6 +18,7 @@ export interface MindElement<T = BaseData> extends PlaitElement {
fill?: string;
strokeColor?: string;
strokeWidth?: number;
strokeStyle?: StrokeStyle;
shape?: MindElementShape;

// link style attributes
Expand Down
13 changes: 9 additions & 4 deletions packages/mind/src/utils/draw/node-link/abstract-link.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { PlaitBoard, Point, createG, drawLinearPath, getRectangleByElements } from '@plait/core';
import { PlaitBoard, createG, drawLinearPath, getRectangleByElements } from '@plait/core';
import { MindNode } from '../../../interfaces/node';
import { getRectangleByNode } from '../../position/node';
import { HorizontalPlacement, PointPlacement, VerticalPlacement } from '../../../interfaces/types';
import { getLayoutDirection, getPointByPlacement, getXDistanceBetweenPoint, moveXOfPoint, transformPlacement } from '../../point-placement';
import { getAbstractBranchColor, getAbstractBranchWidth, getBranchShapeByMindElement } from '../../node-style/branch';
import { BranchShape } from '../../../interfaces/element';
import { getStrokeStyleByElement } from '../../node-style';
import { getStrokeLineDash } from '@plait/common';

export function drawAbstractLink(board: PlaitBoard, node: MindNode, isHorizontal: boolean) {
const linkPadding = 15;
const branchWidth = getAbstractBranchWidth(board, node.origin);
const branchColor = getAbstractBranchColor(board, node.origin);
const strokeStyle = getStrokeStyleByElement(board, node.origin);
const parent = node.parent;
const branchShape = getBranchShapeByMindElement(board, node.origin);
const abstractRectangle = getRectangleByNode(node);
Expand All @@ -36,7 +39,7 @@ export function drawAbstractLink(board: PlaitBoard, node: MindNode, isHorizontal
bezierEndPoint = moveXOfPoint(bezierEndPoint, linkPadding, linkDirection);
let c2 = moveXOfPoint(bezierEndPoint, curveDistance, linkDirection);
let bezierConnectorPoint = moveXOfPoint(abstractConnectorPoint, -linkPadding, linkDirection);

const strokeLineDash = getStrokeLineDash(strokeStyle, branchWidth);
if (branchShape === BranchShape.polyline) {
const g = createG();
const polyline = drawLinearPath([bezierBeginPoint, c1, bezierConnectorPoint, c2, bezierEndPoint], {
Expand All @@ -45,7 +48,8 @@ export function drawAbstractLink(board: PlaitBoard, node: MindNode, isHorizontal
});
const straightLine = drawLinearPath([abstractConnectorPoint, bezierConnectorPoint], {
stroke: branchColor,
strokeWidth: branchWidth
strokeWidth: branchWidth,
strokeLineDash
});

g.appendChild(polyline);
Expand All @@ -58,7 +62,8 @@ export function drawAbstractLink(board: PlaitBoard, node: MindNode, isHorizontal
`M${bezierBeginPoint[0]},${bezierBeginPoint[1]} Q${c1[0]},${c1[1]} ${bezierConnectorPoint[0]},${bezierConnectorPoint[1]} Q${c2[0]},${c2[1]} ${bezierEndPoint[0]},${bezierEndPoint[1]} M${abstractConnectorPoint[0]},${abstractConnectorPoint[1]} L${bezierConnectorPoint[0]},${bezierConnectorPoint[1]}`,
{
stroke: branchColor,
strokeWidth: branchWidth
strokeWidth: branchWidth,
strokeLineDash
}
);
return link;
Expand Down
10 changes: 6 additions & 4 deletions packages/mind/src/utils/draw/node-link/draw-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import { drawIndentedLink } from './indented-link';
import { drawLogicLink } from './logic-link';
import { MindElement } from '../../../interfaces/element';
import { MindNode } from '../../../interfaces/node';
import { StrokeStyle } from '@plait/common';

export function drawLink(
board: PlaitBoard,
parentNode: MindNode,
node: MindNode,
isHorizontal: boolean,
needDrawUnderline?: boolean,
defaultStroke?: string,
defaultStrokeWidth?: number
defaultStrokeColor?: string,
defaultStrokeWidth?: number,
defaultStrokeStyle?: StrokeStyle
) {
return MindElement.isIndentedLayout(parentNode.origin)
? drawIndentedLink(board, parentNode, node, defaultStroke, needDrawUnderline, defaultStrokeWidth)
: drawLogicLink(board, parentNode, node, isHorizontal, defaultStroke, defaultStrokeWidth);
? drawIndentedLink(board, parentNode, node, needDrawUnderline, defaultStrokeColor, defaultStrokeWidth, defaultStrokeStyle)
: drawLogicLink(board, parentNode, node, isHorizontal, defaultStrokeColor, defaultStrokeWidth, defaultStrokeStyle);
}
19 changes: 11 additions & 8 deletions packages/mind/src/utils/draw/node-link/indented-link.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { pointsOnBezierCurves } from 'points-on-curve';
import { MindNode } from '../../../interfaces/node';
import { PlaitBoard, Point, drawBezierPath, drawLinearPath } from '@plait/core';
import { getShapeByElement, getRectangleByNode, isChildUp } from '../..';
import { getShapeByElement, getRectangleByNode, isChildUp, getStrokeStyleByElement } from '../..';
import { getBranchColorByMindElement, getBranchShapeByMindElement, getBranchWidthByMindElement } from '../../node-style/branch';
import { BranchShape, MindElementShape } from '../../../interfaces/element';
import { getStrokeLineDash, StrokeStyle } from '@plait/common';

export function drawIndentedLink(
board: PlaitBoard,
parent: MindNode,
child: MindNode,
defaultStroke: string | null = null,
needDrawUnderline = true,
defaultStrokeWidth?: number
defaultStrokeColor: string | null = null,
defaultStrokeWidth?: number,
defaultStrokeStyle?: StrokeStyle
) {
const branchShape = getBranchShapeByMindElement(board, parent.origin);
const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, parent.origin);
const branchColor = defaultStroke || getBranchColorByMindElement(board, child.origin);
const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, child.origin);
const branchColor = defaultStrokeColor || getBranchColorByMindElement(board, child.origin);
const strokeStyle = defaultStrokeStyle || getStrokeStyleByElement(board, child.origin);

const isUnderlineShape = (getShapeByElement(board, child.origin) as MindElementShape) === MindElementShape.underline;
let beginX,
Expand Down Expand Up @@ -46,7 +49,7 @@ export function drawIndentedLink(
isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
];

const strokeLineDash = getStrokeLineDash(strokeStyle, branchWidth);
if (branchShape === BranchShape.polyline) {
const polylinePoints = [
[beginX, beginY],
Expand All @@ -55,9 +58,9 @@ export function drawIndentedLink(
isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
];

return drawLinearPath(polylinePoints as Point[], { stroke: branchColor, strokeWidth: branchWidth });
return drawLinearPath(polylinePoints as Point[], { stroke: branchColor, strokeWidth: branchWidth, strokeLineDash });
}

const points = pointsOnBezierCurves(curve, 0.001);
return drawBezierPath(points as Point[], { stroke: branchColor, strokeWidth: branchWidth });
return drawBezierPath(points as Point[], { stroke: branchColor, strokeWidth: branchWidth, strokeLineDash });
}
29 changes: 19 additions & 10 deletions packages/mind/src/utils/draw/node-link/logic-link.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { pointsOnBezierCurves } from 'points-on-curve';
import { MindNode } from '../../../interfaces/node';
import { PlaitBoard, Point, drawLinearPath } from '@plait/core';
import { getRectangleByNode, getShapeByElement } from '../..';
import { PlaitBoard, Point, drawLinearPath, setStrokeLinecap } from '@plait/core';
import { getRectangleByNode, getShapeByElement, getStrokeStyleByElement } from '../..';
import { getLayoutDirection, getPointByPlacement, moveXOfPoint, transformPlacement } from '../../point-placement';
import { HorizontalPlacement, PointPlacement, VerticalPlacement } from '../../../interfaces/types';
import { getBranchColorByMindElement, getBranchShapeByMindElement, getBranchWidthByMindElement } from '../../node-style/branch';
import { BranchShape, MindElementShape } from '../../../interfaces/element';
import { getStrokeLineDash, StrokeStyle } from '@plait/common';

export function drawLogicLink(
board: PlaitBoard,
parent: MindNode,
node: MindNode,
isHorizontal: boolean,
defaultStroke: string | null = null,
defaultStrokeWidth?: number
defaultStrokeColor: string | null = null,
defaultStrokeWidth?: number,
defaultStrokeStyle?: StrokeStyle
) {
const branchShape = getBranchShapeByMindElement(board, parent.origin);
const branchColor = defaultStroke || getBranchColorByMindElement(board, node.origin);
const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, parent.origin);
const branchColor = defaultStrokeColor || getBranchColorByMindElement(board, node.origin);
const branchWidth = defaultStrokeWidth || getBranchWidthByMindElement(board, node.origin);
const strokeStyle = defaultStrokeStyle || getStrokeStyleByElement(board, node.origin);
const hasStraightLine = branchShape === BranchShape.polyline ? true : !parent.origin.isRoot;
const parentShape = getShapeByElement(board, parent.origin);
const shape = getShapeByElement(board, node.origin);
Expand Down Expand Up @@ -64,9 +67,10 @@ export function drawLogicLink(
// ④ underline shape and horizontal
const underlineEnd = moveXOfPoint(endPoint, nodeClient.width, linkDirection);
const underline: Point[] = hasUnderlineShape && isHorizontal ? [underlineEnd, underlineEnd, underlineEnd] : [];

const points = pointsOnBezierCurves([...straightLine, ...curve, ...underline]);

const strokeLineDash = getStrokeLineDash(strokeStyle, branchWidth);
console.log(`strokeStyle: ${strokeStyle}, strokeLineDash: `, strokeLineDash);
let linkG: SVGGElement;
if (branchShape === BranchShape.polyline) {
const buffer = 8;
const movePoint = moveXOfPoint(beginPoint2, buffer, linkDirection);
Expand All @@ -77,7 +81,12 @@ export function drawLogicLink(
endPoint,
...underline
];
return drawLinearPath(polylinePoints as Point[], { stroke: branchColor, strokeWidth: branchWidth });
linkG = drawLinearPath(polylinePoints as Point[], { stroke: branchColor, strokeWidth: branchWidth, strokeLineDash });
} else {
linkG = PlaitBoard.getRoughSVG(board).curve(points as any, { stroke: branchColor, strokeWidth: branchWidth, strokeLineDash });
}
if (strokeStyle === StrokeStyle.dotted) {
setStrokeLinecap(linkG, 'round');
}
return PlaitBoard.getRoughSVG(board).curve(points as any, { stroke: branchColor, strokeWidth: branchWidth });
return linkG;
}
Loading
Loading