@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.cjs
CHANGED
|
@@ -92,6 +92,12 @@ var ORIGIN_FRACTION = {
|
|
|
92
92
|
top: 0,
|
|
93
93
|
bottom: 1
|
|
94
94
|
};
|
|
95
|
+
function originFraction(value, fallback = 0) {
|
|
96
|
+
if (value === void 0 || value === null || value === "") return fallback;
|
|
97
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : fallback;
|
|
98
|
+
const named = ORIGIN_FRACTION[String(value).trim().toLowerCase()];
|
|
99
|
+
return named === void 0 ? fallback : named;
|
|
100
|
+
}
|
|
95
101
|
function pathPlaceOrigin(object, bounds) {
|
|
96
102
|
if (!bounds) {
|
|
97
103
|
return { left: num(object.left), top: num(object.top) };
|
|
@@ -104,8 +110,8 @@ function pathPlaceOrigin(object, bounds) {
|
|
|
104
110
|
const height = bounds.height;
|
|
105
111
|
const scaleX = Math.abs(normalizeScale(num(object.scaleX, 1) || 1, width));
|
|
106
112
|
const scaleY = Math.abs(normalizeScale(num(object.scaleY, 1) || 1, height));
|
|
107
|
-
const fractionX =
|
|
108
|
-
const fractionY =
|
|
113
|
+
const fractionX = originFraction(object.originX);
|
|
114
|
+
const fractionY = originFraction(object.originY);
|
|
109
115
|
const angle = num(object.angle) * Math.PI / 180;
|
|
110
116
|
const cos = Math.cos(angle);
|
|
111
117
|
const sin = Math.sin(angle);
|
|
@@ -215,8 +221,13 @@ function convertPathData(pathData, object) {
|
|
|
215
221
|
}).join(" ");
|
|
216
222
|
}
|
|
217
223
|
function aroundOf(object) {
|
|
218
|
-
const
|
|
219
|
-
|
|
224
|
+
const axisOf = (fraction, low, center, high) => {
|
|
225
|
+
if (fraction <= 0.25) return low;
|
|
226
|
+
if (fraction >= 0.75) return high;
|
|
227
|
+
return center;
|
|
228
|
+
};
|
|
229
|
+
const originX = axisOf(originFraction(object.originX), "left", "center", "right");
|
|
230
|
+
const originY = axisOf(originFraction(object.originY), "top", "center", "bottom");
|
|
220
231
|
const map = {
|
|
221
232
|
left: { top: "top-left", center: "left", bottom: "bottom-left" },
|
|
222
233
|
center: { top: "top", center: "center", bottom: "bottom" },
|
|
@@ -339,13 +350,6 @@ function normalizeSizeSign(object) {
|
|
|
339
350
|
}
|
|
340
351
|
|
|
341
352
|
// src/attributes/transform.js
|
|
342
|
-
var ORIGIN_FRACTION2 = {
|
|
343
|
-
left: 0,
|
|
344
|
-
center: 0.5,
|
|
345
|
-
right: 1,
|
|
346
|
-
top: 0,
|
|
347
|
-
bottom: 1
|
|
348
|
-
};
|
|
349
353
|
var PATH_PLACED_TYPES = ["polyline", "polygon", "line"];
|
|
350
354
|
function bakePointsScale(node2, object, scaleX, scaleY) {
|
|
351
355
|
if (!PATH_PLACED_TYPES.includes(object.type)) return false;
|
|
@@ -421,9 +425,8 @@ function applyPosition(node2, object, scaleX, scaleY) {
|
|
|
421
425
|
if (PATH_PLACED_TYPES.includes(object.type)) return;
|
|
422
426
|
const width = num(object.width);
|
|
423
427
|
const height = num(object.height);
|
|
424
|
-
const fractionX =
|
|
425
|
-
const fractionY =
|
|
426
|
-
if (fractionX === void 0 || fractionY === void 0) return;
|
|
428
|
+
const fractionX = originFraction(object.originX);
|
|
429
|
+
const fractionY = originFraction(object.originY);
|
|
427
430
|
const single = scaleX > 0 && scaleY > 0 && !num(node2.rotation, 0);
|
|
428
431
|
if (single) return;
|
|
429
432
|
const angle = num(node2.rotation, 0) * Math.PI / 180;
|
|
@@ -645,6 +648,7 @@ function applyPaint(node2, object, ctx) {
|
|
|
645
648
|
if (strokeWidth !== void 0) {
|
|
646
649
|
node2.strokeWidth = strokeWidth;
|
|
647
650
|
}
|
|
651
|
+
node2.strokeScaleFixed = true;
|
|
648
652
|
if (Array.isArray(object.strokeDashArray) && object.strokeDashArray.length) {
|
|
649
653
|
node2.dashPattern = object.strokeDashArray;
|
|
650
654
|
}
|
|
@@ -777,9 +781,13 @@ function cornerRadiusOf(object) {
|
|
|
777
781
|
return [Math.max(0, rx || 0), Math.max(0, ry || 0)];
|
|
778
782
|
}
|
|
779
783
|
function convertRect(object, ctx, parent) {
|
|
784
|
+
const width = optionalNum(object.width);
|
|
785
|
+
const height = optionalNum(object.height);
|
|
780
786
|
const rect = node("Rect", {
|
|
781
|
-
|
|
782
|
-
|
|
787
|
+
// Leafer 的 Rect 不给宽高时用默认的 100x100, Fabric 里缺宽高的图元
|
|
788
|
+
// (脏数据 / 没画完的空框)要显式写 0, 否则转出来凭空多出一个 100 的框
|
|
789
|
+
width: width === void 0 ? 0 : width,
|
|
790
|
+
height: height === void 0 ? 0 : height,
|
|
783
791
|
fill: paintOf(object.fill, ctx),
|
|
784
792
|
cornerRadius: cornerRadiusOf(object)
|
|
785
793
|
});
|
|
@@ -789,9 +797,12 @@ function convertRect(object, ctx, parent) {
|
|
|
789
797
|
|
|
790
798
|
// src/elements/ellipse.js
|
|
791
799
|
function convertEllipse(object, ctx, parent) {
|
|
800
|
+
const width = optionalNum(object.width);
|
|
801
|
+
const height = optionalNum(object.height);
|
|
792
802
|
const ellipse = node("Ellipse", {
|
|
793
|
-
|
|
794
|
-
|
|
803
|
+
// 同 Rect: 不写宽高会落到 Leafer 的 100x100 默认尺寸
|
|
804
|
+
width: width === void 0 ? 0 : width,
|
|
805
|
+
height: height === void 0 ? 0 : height,
|
|
795
806
|
fill: paintOf(object.fill, ctx)
|
|
796
807
|
});
|
|
797
808
|
place(ellipse, object, parent);
|
|
@@ -820,8 +831,9 @@ function convertTriangle(object, ctx, parent) {
|
|
|
820
831
|
const w = width || 0;
|
|
821
832
|
const h = height || 0;
|
|
822
833
|
const triangle = node("Polygon", {
|
|
823
|
-
|
|
824
|
-
|
|
834
|
+
// 不写宽高会落到 Leafer 的 100x100 默认尺寸
|
|
835
|
+
width: w,
|
|
836
|
+
height: h,
|
|
825
837
|
// 顶点在正上方,底边贴底:和 Fabric 的三角形一致
|
|
826
838
|
points: [w / 2, 0, w, h, 0, h],
|
|
827
839
|
fill: paintOf(object.fill, ctx),
|
|
@@ -972,7 +984,6 @@ function textProps(object, ctx) {
|
|
|
972
984
|
letterSpacing: convertLetterSpacing(object.charSpacing, object.fontSize),
|
|
973
985
|
fill: object.fill ? paintOf(object.fill, ctx) : "#000000",
|
|
974
986
|
shadow: object.shadow ? convertShadow(object.shadow) : void 0,
|
|
975
|
-
verticalAlign: "middle",
|
|
976
987
|
textDecoration: textDecorationOf(object)
|
|
977
988
|
};
|
|
978
989
|
const backgroundColor = object.backgroundColor || object.textBackgroundColor;
|
|
@@ -989,22 +1000,64 @@ function textProps(object, ctx) {
|
|
|
989
1000
|
}
|
|
990
1001
|
|
|
991
1002
|
// src/elements/text.js
|
|
992
|
-
function
|
|
1003
|
+
function textLines(object) {
|
|
1004
|
+
const content = object.text === void 0 ? "" : String(object.text);
|
|
1005
|
+
return Math.max(1, content.split("\n").length);
|
|
1006
|
+
}
|
|
1007
|
+
function ratioFromHeight(object) {
|
|
993
1008
|
const fontSize = optionalNum(object.fontSize);
|
|
994
1009
|
const height = optionalNum(object.height);
|
|
995
1010
|
if (!fontSize || !height) return void 0;
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1011
|
+
const ratio = Math.round(height / (fontSize * textLines(object)) * 1e3) / 1e3;
|
|
1012
|
+
return ratio > 0.8 && ratio < 1.6 ? ratio : void 0;
|
|
1013
|
+
}
|
|
1014
|
+
function estimateLineHeight(object) {
|
|
1015
|
+
const ratio = ratioFromHeight(object);
|
|
1016
|
+
return ratio === void 0 ? void 0 : { type: "percent", value: ratio };
|
|
1017
|
+
}
|
|
1018
|
+
function lineHeightPx(lineHeight, fontSize) {
|
|
1019
|
+
if (lineHeight === void 0) return fontSize * 1.16;
|
|
1020
|
+
if (typeof lineHeight === "number") return lineHeight;
|
|
1021
|
+
if (lineHeight && lineHeight.type === "percent") return fontSize * (Number(lineHeight.value) || 0);
|
|
1022
|
+
return void 0;
|
|
1023
|
+
}
|
|
1024
|
+
function fitLineHeight(props, object) {
|
|
1025
|
+
if (props.textWrap !== "none") return props.lineHeight;
|
|
1026
|
+
const fontSize = optionalNum(object.fontSize);
|
|
1027
|
+
const height = optionalNum(object.height);
|
|
1028
|
+
const ratio = ratioFromHeight(object);
|
|
1029
|
+
if (!fontSize || !height || ratio === void 0) return props.lineHeight;
|
|
1030
|
+
const current = lineHeightPx(props.lineHeight, fontSize);
|
|
1031
|
+
if (current === void 0 || current * textLines(object) <= height + 0.5) return props.lineHeight;
|
|
1000
1032
|
return { type: "percent", value: ratio };
|
|
1001
1033
|
}
|
|
1034
|
+
function textLineHeight(props, object) {
|
|
1035
|
+
return fitLineHeight({ ...props, lineHeight: { type: "percent", value: 1 } }, object);
|
|
1036
|
+
}
|
|
1037
|
+
function textboxLineHeight(object) {
|
|
1038
|
+
const fontSize = optionalNum(object.fontSize);
|
|
1039
|
+
const height = optionalNum(object.height);
|
|
1040
|
+
const lines = textLines(object);
|
|
1041
|
+
if (lines > 1 && fontSize && height) {
|
|
1042
|
+
const ratio = Math.round(height / (fontSize * lines) * 1e3) / 1e3;
|
|
1043
|
+
if (ratio > 0.8 && ratio < 2.5) {
|
|
1044
|
+
return { type: "percent", value: ratio };
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
return { type: "percent", value: 1 };
|
|
1048
|
+
}
|
|
1002
1049
|
function isIText(object) {
|
|
1003
1050
|
return object.type === "i-text" || object.type === "itext";
|
|
1004
1051
|
}
|
|
1005
1052
|
function convertText(object, ctx, parent) {
|
|
1006
1053
|
const props = textProps(object, ctx);
|
|
1007
1054
|
const itext = isIText(object);
|
|
1055
|
+
if (!itext && object.type === "textbox") {
|
|
1056
|
+
props.lineHeight = textboxLineHeight(object);
|
|
1057
|
+
} else if (!itext) {
|
|
1058
|
+
props.verticalAlign = "top";
|
|
1059
|
+
props.lineHeight = textLineHeight(props, object);
|
|
1060
|
+
}
|
|
1008
1061
|
const text = itext ? node("IText", {
|
|
1009
1062
|
...props,
|
|
1010
1063
|
lineHeight: props.lineHeight || estimateLineHeight(object)
|
|
@@ -1094,7 +1147,7 @@ function stripChildPageActions(object, parentPageActionEvents) {
|
|
|
1094
1147
|
}
|
|
1095
1148
|
return object;
|
|
1096
1149
|
}
|
|
1097
|
-
function
|
|
1150
|
+
function originFraction2(around) {
|
|
1098
1151
|
if (!around) return { x: 0, y: 0 };
|
|
1099
1152
|
if (typeof around === "object") {
|
|
1100
1153
|
const x = Number(around.x);
|
|
@@ -1137,7 +1190,7 @@ function contentBox(children, offsetX = 0, offsetY = 0) {
|
|
|
1137
1190
|
if (!child || typeof child !== "object") return;
|
|
1138
1191
|
const x = Number.isFinite(Number(child.x)) ? Number(child.x) : 0;
|
|
1139
1192
|
const y = Number.isFinite(Number(child.y)) ? Number(child.y) : 0;
|
|
1140
|
-
const origin =
|
|
1193
|
+
const origin = originFraction2(child.around);
|
|
1141
1194
|
const size = nodeSize(child);
|
|
1142
1195
|
const left = offsetX + x - size.width * origin.x;
|
|
1143
1196
|
const top = offsetY + y - size.height * origin.y;
|