@xrubik/fabric-to-leafer 0.1.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +81 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +81 -28
- package/dist/index.mjs.map +1 -1
- package/dist/leafer.cjs +81 -28
- package/dist/leafer.cjs.map +1 -1
- package/dist/leafer.mjs +81 -28
- package/dist/leafer.mjs.map +1 -1
- package/package.json +2 -2
package/dist/leafer.mjs
CHANGED
|
@@ -65,6 +65,12 @@ var ORIGIN_FRACTION = {
|
|
|
65
65
|
top: 0,
|
|
66
66
|
bottom: 1
|
|
67
67
|
};
|
|
68
|
+
function originFraction(value, fallback = 0) {
|
|
69
|
+
if (value === void 0 || value === null || value === "") return fallback;
|
|
70
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : fallback;
|
|
71
|
+
const named = ORIGIN_FRACTION[String(value).trim().toLowerCase()];
|
|
72
|
+
return named === void 0 ? fallback : named;
|
|
73
|
+
}
|
|
68
74
|
function pathPlaceOrigin(object, bounds) {
|
|
69
75
|
if (!bounds) {
|
|
70
76
|
return { left: num(object.left), top: num(object.top) };
|
|
@@ -77,8 +83,8 @@ function pathPlaceOrigin(object, bounds) {
|
|
|
77
83
|
const height = bounds.height;
|
|
78
84
|
const scaleX = Math.abs(normalizeScale(num(object.scaleX, 1) || 1, width));
|
|
79
85
|
const scaleY = Math.abs(normalizeScale(num(object.scaleY, 1) || 1, height));
|
|
80
|
-
const fractionX =
|
|
81
|
-
const fractionY =
|
|
86
|
+
const fractionX = originFraction(object.originX);
|
|
87
|
+
const fractionY = originFraction(object.originY);
|
|
82
88
|
const angle = num(object.angle) * Math.PI / 180;
|
|
83
89
|
const cos = Math.cos(angle);
|
|
84
90
|
const sin = Math.sin(angle);
|
|
@@ -188,8 +194,13 @@ function convertPathData(pathData, object) {
|
|
|
188
194
|
}).join(" ");
|
|
189
195
|
}
|
|
190
196
|
function aroundOf(object) {
|
|
191
|
-
const
|
|
192
|
-
|
|
197
|
+
const axisOf = (fraction, low, center, high) => {
|
|
198
|
+
if (fraction <= 0.25) return low;
|
|
199
|
+
if (fraction >= 0.75) return high;
|
|
200
|
+
return center;
|
|
201
|
+
};
|
|
202
|
+
const originX = axisOf(originFraction(object.originX), "left", "center", "right");
|
|
203
|
+
const originY = axisOf(originFraction(object.originY), "top", "center", "bottom");
|
|
193
204
|
const map = {
|
|
194
205
|
left: { top: "top-left", center: "left", bottom: "bottom-left" },
|
|
195
206
|
center: { top: "top", center: "center", bottom: "bottom" },
|
|
@@ -312,13 +323,6 @@ function normalizeSizeSign(object) {
|
|
|
312
323
|
}
|
|
313
324
|
|
|
314
325
|
// src/attributes/transform.js
|
|
315
|
-
var ORIGIN_FRACTION2 = {
|
|
316
|
-
left: 0,
|
|
317
|
-
center: 0.5,
|
|
318
|
-
right: 1,
|
|
319
|
-
top: 0,
|
|
320
|
-
bottom: 1
|
|
321
|
-
};
|
|
322
326
|
var PATH_PLACED_TYPES = ["polyline", "polygon", "line"];
|
|
323
327
|
function bakePointsScale(node2, object, scaleX, scaleY) {
|
|
324
328
|
if (!PATH_PLACED_TYPES.includes(object.type)) return false;
|
|
@@ -394,9 +398,8 @@ function applyPosition(node2, object, scaleX, scaleY) {
|
|
|
394
398
|
if (PATH_PLACED_TYPES.includes(object.type)) return;
|
|
395
399
|
const width = num(object.width);
|
|
396
400
|
const height = num(object.height);
|
|
397
|
-
const fractionX =
|
|
398
|
-
const fractionY =
|
|
399
|
-
if (fractionX === void 0 || fractionY === void 0) return;
|
|
401
|
+
const fractionX = originFraction(object.originX);
|
|
402
|
+
const fractionY = originFraction(object.originY);
|
|
400
403
|
const single = scaleX > 0 && scaleY > 0 && !num(node2.rotation, 0);
|
|
401
404
|
if (single) return;
|
|
402
405
|
const angle = num(node2.rotation, 0) * Math.PI / 180;
|
|
@@ -618,6 +621,7 @@ function applyPaint(node2, object, ctx) {
|
|
|
618
621
|
if (strokeWidth !== void 0) {
|
|
619
622
|
node2.strokeWidth = strokeWidth;
|
|
620
623
|
}
|
|
624
|
+
node2.strokeScaleFixed = true;
|
|
621
625
|
if (Array.isArray(object.strokeDashArray) && object.strokeDashArray.length) {
|
|
622
626
|
node2.dashPattern = object.strokeDashArray;
|
|
623
627
|
}
|
|
@@ -750,9 +754,13 @@ function cornerRadiusOf(object) {
|
|
|
750
754
|
return [Math.max(0, rx || 0), Math.max(0, ry || 0)];
|
|
751
755
|
}
|
|
752
756
|
function convertRect(object, ctx, parent) {
|
|
757
|
+
const width = optionalNum(object.width);
|
|
758
|
+
const height = optionalNum(object.height);
|
|
753
759
|
const rect = node("Rect", {
|
|
754
|
-
|
|
755
|
-
|
|
760
|
+
// Leafer 的 Rect 不给宽高时用默认的 100x100, Fabric 里缺宽高的图元
|
|
761
|
+
// (脏数据 / 没画完的空框)要显式写 0, 否则转出来凭空多出一个 100 的框
|
|
762
|
+
width: width === void 0 ? 0 : width,
|
|
763
|
+
height: height === void 0 ? 0 : height,
|
|
756
764
|
fill: paintOf(object.fill, ctx),
|
|
757
765
|
cornerRadius: cornerRadiusOf(object)
|
|
758
766
|
});
|
|
@@ -762,9 +770,12 @@ function convertRect(object, ctx, parent) {
|
|
|
762
770
|
|
|
763
771
|
// src/elements/ellipse.js
|
|
764
772
|
function convertEllipse(object, ctx, parent) {
|
|
773
|
+
const width = optionalNum(object.width);
|
|
774
|
+
const height = optionalNum(object.height);
|
|
765
775
|
const ellipse = node("Ellipse", {
|
|
766
|
-
|
|
767
|
-
|
|
776
|
+
// 同 Rect: 不写宽高会落到 Leafer 的 100x100 默认尺寸
|
|
777
|
+
width: width === void 0 ? 0 : width,
|
|
778
|
+
height: height === void 0 ? 0 : height,
|
|
768
779
|
fill: paintOf(object.fill, ctx)
|
|
769
780
|
});
|
|
770
781
|
place(ellipse, object, parent);
|
|
@@ -793,8 +804,9 @@ function convertTriangle(object, ctx, parent) {
|
|
|
793
804
|
const w = width || 0;
|
|
794
805
|
const h = height || 0;
|
|
795
806
|
const triangle = node("Polygon", {
|
|
796
|
-
|
|
797
|
-
|
|
807
|
+
// 不写宽高会落到 Leafer 的 100x100 默认尺寸
|
|
808
|
+
width: w,
|
|
809
|
+
height: h,
|
|
798
810
|
// 顶点在正上方,底边贴底:和 Fabric 的三角形一致
|
|
799
811
|
points: [w / 2, 0, w, h, 0, h],
|
|
800
812
|
fill: paintOf(object.fill, ctx),
|
|
@@ -945,7 +957,6 @@ function textProps(object, ctx) {
|
|
|
945
957
|
letterSpacing: convertLetterSpacing(object.charSpacing, object.fontSize),
|
|
946
958
|
fill: object.fill ? paintOf(object.fill, ctx) : "#000000",
|
|
947
959
|
shadow: object.shadow ? convertShadow(object.shadow) : void 0,
|
|
948
|
-
verticalAlign: "middle",
|
|
949
960
|
textDecoration: textDecorationOf(object)
|
|
950
961
|
};
|
|
951
962
|
const backgroundColor = object.backgroundColor || object.textBackgroundColor;
|
|
@@ -962,22 +973,64 @@ function textProps(object, ctx) {
|
|
|
962
973
|
}
|
|
963
974
|
|
|
964
975
|
// src/elements/text.js
|
|
965
|
-
function
|
|
976
|
+
function textLines(object) {
|
|
977
|
+
const content = object.text === void 0 ? "" : String(object.text);
|
|
978
|
+
return Math.max(1, content.split("\n").length);
|
|
979
|
+
}
|
|
980
|
+
function ratioFromHeight(object) {
|
|
966
981
|
const fontSize = optionalNum(object.fontSize);
|
|
967
982
|
const height = optionalNum(object.height);
|
|
968
983
|
if (!fontSize || !height) return void 0;
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
984
|
+
const ratio = Math.round(height / (fontSize * textLines(object)) * 1e3) / 1e3;
|
|
985
|
+
return ratio > 0.8 && ratio < 1.6 ? ratio : void 0;
|
|
986
|
+
}
|
|
987
|
+
function estimateLineHeight(object) {
|
|
988
|
+
const ratio = ratioFromHeight(object);
|
|
989
|
+
return ratio === void 0 ? void 0 : { type: "percent", value: ratio };
|
|
990
|
+
}
|
|
991
|
+
function lineHeightPx(lineHeight, fontSize) {
|
|
992
|
+
if (lineHeight === void 0) return fontSize * 1.16;
|
|
993
|
+
if (typeof lineHeight === "number") return lineHeight;
|
|
994
|
+
if (lineHeight && lineHeight.type === "percent") return fontSize * (Number(lineHeight.value) || 0);
|
|
995
|
+
return void 0;
|
|
996
|
+
}
|
|
997
|
+
function fitLineHeight(props, object) {
|
|
998
|
+
if (props.textWrap !== "none") return props.lineHeight;
|
|
999
|
+
const fontSize = optionalNum(object.fontSize);
|
|
1000
|
+
const height = optionalNum(object.height);
|
|
1001
|
+
const ratio = ratioFromHeight(object);
|
|
1002
|
+
if (!fontSize || !height || ratio === void 0) return props.lineHeight;
|
|
1003
|
+
const current = lineHeightPx(props.lineHeight, fontSize);
|
|
1004
|
+
if (current === void 0 || current * textLines(object) <= height + 0.5) return props.lineHeight;
|
|
973
1005
|
return { type: "percent", value: ratio };
|
|
974
1006
|
}
|
|
1007
|
+
function textLineHeight(props, object) {
|
|
1008
|
+
return fitLineHeight({ ...props, lineHeight: { type: "percent", value: 1 } }, object);
|
|
1009
|
+
}
|
|
1010
|
+
function textboxLineHeight(object) {
|
|
1011
|
+
const fontSize = optionalNum(object.fontSize);
|
|
1012
|
+
const height = optionalNum(object.height);
|
|
1013
|
+
const lines = textLines(object);
|
|
1014
|
+
if (lines > 1 && fontSize && height) {
|
|
1015
|
+
const ratio = Math.round(height / (fontSize * lines) * 1e3) / 1e3;
|
|
1016
|
+
if (ratio > 0.8 && ratio < 2.5) {
|
|
1017
|
+
return { type: "percent", value: ratio };
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
return { type: "percent", value: 1 };
|
|
1021
|
+
}
|
|
975
1022
|
function isIText(object) {
|
|
976
1023
|
return object.type === "i-text" || object.type === "itext";
|
|
977
1024
|
}
|
|
978
1025
|
function convertText(object, ctx, parent) {
|
|
979
1026
|
const props = textProps(object, ctx);
|
|
980
1027
|
const itext = isIText(object);
|
|
1028
|
+
if (!itext && object.type === "textbox") {
|
|
1029
|
+
props.lineHeight = textboxLineHeight(object);
|
|
1030
|
+
} else if (!itext) {
|
|
1031
|
+
props.verticalAlign = "top";
|
|
1032
|
+
props.lineHeight = textLineHeight(props, object);
|
|
1033
|
+
}
|
|
981
1034
|
const text = itext ? node("IText", {
|
|
982
1035
|
...props,
|
|
983
1036
|
lineHeight: props.lineHeight || estimateLineHeight(object)
|
|
@@ -1067,7 +1120,7 @@ function stripChildPageActions(object, parentPageActionEvents) {
|
|
|
1067
1120
|
}
|
|
1068
1121
|
return object;
|
|
1069
1122
|
}
|
|
1070
|
-
function
|
|
1123
|
+
function originFraction2(around) {
|
|
1071
1124
|
if (!around) return { x: 0, y: 0 };
|
|
1072
1125
|
if (typeof around === "object") {
|
|
1073
1126
|
const x = Number(around.x);
|
|
@@ -1110,7 +1163,7 @@ function contentBox(children, offsetX = 0, offsetY = 0) {
|
|
|
1110
1163
|
if (!child || typeof child !== "object") return;
|
|
1111
1164
|
const x = Number.isFinite(Number(child.x)) ? Number(child.x) : 0;
|
|
1112
1165
|
const y = Number.isFinite(Number(child.y)) ? Number(child.y) : 0;
|
|
1113
|
-
const origin =
|
|
1166
|
+
const origin = originFraction2(child.around);
|
|
1114
1167
|
const size = nodeSize(child);
|
|
1115
1168
|
const left = offsetX + x - size.width * origin.x;
|
|
1116
1169
|
const top = offsetY + y - size.height * origin.y;
|