Skip to content

Commit 2f16b18

Browse files
committed
fix: 修复大部分单路径识别的问题
1 parent efe24ae commit 2f16b18

File tree

10 files changed

+2211
-64
lines changed

10 files changed

+2211
-64
lines changed

example/components/Icon.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,6 @@ const IconSymbol: FC = () => {
754754
{/*<RestOutlined />*/}
755755
{/*<RobotOutlined />*/}
756756
{/*<RocketOutlined />*/}
757-
758757
{/*<SafetyCertificateOutlined />*/}
759758
{/*<SafetyOutlined />*/}
760759
{/*<ScanOutlined />*/}
@@ -803,8 +802,11 @@ const IconSymbol: FC = () => {
803802
{/*<VideoCameraOutlined />*/}
804803
{/*<WalletOutlined />*/}
805804
{/*<WifiOutlined />*/}
805+
{/*<BorderlessTableOutlined />*/}
806806
{/*<WomanOutlined />*/}
807-
807+
{/*<BehanceOutlined />*/}
808+
{/*<DropboxOutlined />*/}
809+
{/*<DeploymentUnitOutlined />*/}
808810
{/* 有错误的 SVG */}
809811
{/*<UpCircleOutlined />*/}
810812
{/*<DownCircleOutlined />*/}
@@ -834,11 +836,8 @@ const IconSymbol: FC = () => {
834836
{/*<YoutubeOutlined />*/}
835837
{/*<CodepenCircleOutlined />*/}
836838
{/*<AliyunOutlined />*/}
837-
{/*<BehanceOutlined />*/}
838-
<DropboxOutlined />
839839
{/*<LinkedinOutlined />*/}
840840
{/*<AimOutlined />*/}
841-
{/* <BorderlessTableOutlined />*/}
842841
{/*<BugOutlined />*/}
843842
{/*<CloudDownloadOutlined />*/}
844843
{/*<CloudServerOutlined />*/}
@@ -847,7 +846,6 @@ const IconSymbol: FC = () => {
847846
{/* <CommentOutlined />*/}
848847
{/* <ConsoleSqlOutlined />*/}
849848
{/*<EyeInvisibleOutlined />*/}
850-
{/*<DeploymentUnitOutlined /> 报错*/}
851849
{/* <FileGifOutlined />*/}
852850
{/*<DeliveredProcedureOutlined />*/}
853851
{/*<FieldTimeOutlined />*/}
@@ -866,7 +864,6 @@ const IconSymbol: FC = () => {
866864
{/*<VerifiedOutlined />*/}
867865
{/*<VideoCameraAddOutlined />*/}
868866
{/*<WhatsAppOutlined />*/}
869-
870867
{/*</Col>*/}
871868
</Row>
872869
);

src/function/nodeToSketchLayers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { defaultNodeStyle } from '../model/utils';
22

3-
import transferToSvg from '../parser/svg';
3+
import parserToSvg from '../parser/svg';
44
import transferToShape from '../parser/shape';
55
import transferToText from '../parser/text';
66
import parserPseudo from '../parser/pseudo';
@@ -98,7 +98,7 @@ const nodeToSketchLayers = (node: Element): AnyLayer[] => {
9898

9999
// 转换为 SVG
100100
if (isSVG) {
101-
const svg = transferToSvg(node);
101+
const svg = parserToSvg(node);
102102
console.log('转换为 Svg: ', svg);
103103
layers.push(svg);
104104

src/helpers/svg.ts

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const SVG_STYLE_PROPERTIES = [
8282
['writing-mode', 'horizontal-tb'],
8383
];
8484

85-
function inlineStyles(node) {
85+
export function inlineStyles(node) {
8686
const styles = getComputedStyle(node);
8787

8888
SVG_STYLE_PROPERTIES.forEach((prop) => {
@@ -100,7 +100,7 @@ function inlineStyles(node) {
100100
});
101101
}
102102

103-
function getUseReplacement(node) {
103+
export function getUseReplacement(node) {
104104
const href = node.href.baseVal;
105105
// TODO this will only work for internal references
106106
let refNode = null;
@@ -132,37 +132,3 @@ function getUseReplacement(node) {
132132

133133
return resultNode;
134134
}
135-
136-
// NOTE: this code modifies the original node by inlining all styles
137-
// this is not ideal and probably fixable
138-
export function getSVGString(svgNode: Element): string {
139-
const queue = Array.from(svgNode.children);
140-
141-
while (queue.length) {
142-
const node = queue.pop();
143-
144-
if (
145-
!(node instanceof SVGElement) ||
146-
node instanceof SVGDefsElement ||
147-
node instanceof SVGTitleElement
148-
) {
149-
continue;
150-
}
151-
152-
if (node instanceof SVGUseElement) {
153-
const replacement = getUseReplacement(node);
154-
155-
if (replacement) {
156-
node.parentNode!.replaceChild(replacement, node);
157-
queue.push(replacement);
158-
}
159-
continue;
160-
}
161-
162-
inlineStyles(node);
163-
164-
Array.from(node.children).forEach((child) => queue.push(child));
165-
}
166-
167-
return svgNode.outerHTML;
168-
}

src/model/Layer/ShapePath.ts

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class ShapePath extends Base {
5555
*/
5656
booleanOperation: SketchFormat.BooleanOperation =
5757
SketchFormat.BooleanOperation.NA;
58+
5859
/**
5960
* 转为 Sketch JSON 文件
6061
*/
@@ -104,36 +105,38 @@ class ShapePath extends Base {
104105
let curveFromPoint: { x: number; y: number } = point;
105106
let curveToPoint: { x: number; y: number } = point;
106107

108+
// 判断 CurveTo
107109
// 如果自身点是 Curve 点
108110
if (thisPoint.type === SVGPathData.CURVE_TO) {
109111
curveToPoint = { x: thisPoint.x2, y: thisPoint.y2 };
110112
hasCurveTo = true;
111113
}
112114

115+
// 判断 CurveFrom
116+
113117
// 如果下一个点是 Curve 点
114118
if (nextPoint.type === SVGPathData.CURVE_TO) {
115119
hasCurveFrom = true;
116120
curveFromPoint = { x: nextPoint.x1, y: nextPoint.y1 };
117121
}
118122

119123
// 确认曲线模式
120-
const curveMode =
121-
// 既有前 也有后 就不对称
122-
hasCurveFrom && hasCurveTo
123-
? SketchFormat.CurveMode.Asymmetric
124-
: // 否则 有前或有后 就是弯的
125-
hasCurveFrom || hasCurveTo
126-
? SketchFormat.CurveMode.Disconnected
127-
: // 不然就是直的
128-
SketchFormat.CurveMode.Straight;
124+
const curveMode = this.judgeCurveMode({
125+
hasCurveFrom,
126+
hasCurveTo,
127+
curveFromPoint,
128+
curveToPoint,
129+
thisPoint,
130+
});
129131

130132
const firstPoint = this.points[0];
131133
if (
132134
// 如果是闭合路径
133135
this.isClosed &&
134136
// 且最后一个点和起点点一样
135137
index === this.points.length - 1 &&
136-
(point.x === firstPoint.x && point.y === firstPoint.y)
138+
(point.x.toFixed(8) === firstPoint.x.toFixed(8) &&
139+
point.y.toFixed(8) === firstPoint.y.toFixed(8))
137140
)
138141
// 则过滤最后一个点
139142
return;
@@ -150,6 +153,58 @@ class ShapePath extends Base {
150153
};
151154
};
152155

156+
/**
157+
* 判断点是否在同一条线上
158+
* @param q 当前点
159+
* @param p1 上一个点
160+
* @param p2 下一个点
161+
*/
162+
private judgeIsOnSameLine = (
163+
q: BezierPoint,
164+
p1: BezierPoint,
165+
p2: BezierPoint
166+
) => {
167+
return (
168+
q.x >= Math.min(p1.x, p2.x) &&
169+
q.x <= Math.max(p1.x, p2.x) &&
170+
(q.y >= Math.min(p1.y, p2.y) && q.y <= Math.max(p1.y, p2.y))
171+
);
172+
};
173+
174+
/**
175+
* 判断曲线模型
176+
* @param hasCurveFrom 是否有前置曲线
177+
* @param hasCurveTo 是否有后置曲线
178+
* @param curveFromPoint 前置曲线点
179+
* @param curveToPoint 后置曲线点
180+
* @param thisPoint 自己这个点
181+
*/
182+
private judgeCurveMode = ({
183+
hasCurveFrom,
184+
hasCurveTo,
185+
curveFromPoint,
186+
curveToPoint,
187+
thisPoint,
188+
}): SketchFormat.CurveMode => {
189+
// 既有前 也有后
190+
if (hasCurveFrom && hasCurveTo) {
191+
// 则是曲线
192+
// 再判断是否在同一条直线上
193+
if (this.judgeIsOnSameLine(thisPoint, curveFromPoint, curveToPoint)) {
194+
// 是的话则是不对称
195+
return SketchFormat.CurveMode.Asymmetric;
196+
}
197+
// 否则就是分离
198+
else return SketchFormat.CurveMode.Disconnected;
199+
} else if (hasCurveFrom || hasCurveTo) {
200+
// 否则 有前或有后 就是弯的
201+
return SketchFormat.CurveMode.Disconnected;
202+
}
203+
204+
// 不然就是直的
205+
else return SketchFormat.CurveMode.Straight;
206+
};
207+
153208
/**
154209
* 获取上下文的点
155210
* @param index

src/model/Layer/Svg.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { BaseLayerParams } from './Base';
66

77
import ShapeGroup, { ShapeGroupType } from './ShapeGroup';
88
import ShapePath from './ShapePath';
9+
import { getUseReplacement, inlineStyles } from '../../helpers/svg';
910

1011
export type SVG = {
1112
_class: 'svg';
@@ -40,18 +41,19 @@ export type BezierPoint = StartPoint | CurvePoint | LinePoint;
4041

4142
interface SvgInitParams extends BaseLayerParams {
4243
path: string;
44+
svgString?: string;
4345
}
4446

4547
/**
4648
* SVG 对象
4749
*/
4850
class Svg extends ShapeGroup {
49-
constructor({ x, y, width, height, path }: SvgInitParams) {
51+
constructor({ x, y, width, height, path, svgString }: SvgInitParams) {
5052
super({ height, width, y, x });
5153
this.class = 'svg';
5254

5355
this.name = 'svg';
54-
this.rawSVGString = path;
56+
this.rawSVGString = svgString;
5557

5658
const { shapes, frame: innerFrame } = Svg.svgPathToShapeGroup(path);
5759

@@ -162,6 +164,44 @@ class Svg extends ShapeGroup {
162164
frame: groupFrame,
163165
};
164166
};
167+
168+
/**
169+
* 将 Svg Node 转为 SvgString
170+
* @param svgNode
171+
*/
172+
static getSVGString = (svgNode: Element): string => {
173+
// NOTE: this code modifies the original node by inlining all styles
174+
// this is not ideal and probably fixable
175+
const queue = Array.from(svgNode.children);
176+
177+
while (queue.length) {
178+
const node = queue.pop();
179+
180+
if (
181+
!(node instanceof SVGElement) ||
182+
node instanceof SVGDefsElement ||
183+
node instanceof SVGTitleElement
184+
) {
185+
continue;
186+
}
187+
188+
if (node instanceof SVGUseElement) {
189+
const replacement = getUseReplacement(node);
190+
191+
if (replacement) {
192+
node.parentNode!.replaceChild(replacement, node);
193+
queue.push(replacement);
194+
}
195+
continue;
196+
}
197+
198+
inlineStyles(node);
199+
200+
Array.from(node.children).forEach((child) => queue.push(child));
201+
}
202+
203+
return svgNode.outerHTML;
204+
};
165205
}
166206

167207
export default Svg;

0 commit comments

Comments
 (0)