@visactor/vrender-core
Version:
## Description
292 lines (276 loc) • 17.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.multiToOneMorph = exports.splitGraphic = exports.cloneGraphic = exports.MultiToOneMorphingPath = exports.oneToMultiMorph = exports.morphPath = exports.MorphingPath = void 0;
const split_path_1 = require("./../common/split-path"), custom_path2d_1 = require("../common/custom-path2d"), animate_1 = require("./animate"), morphing_utils_1 = require("../common/morphing-utils"), application_1 = require("../application"), vutils_1 = require("@visactor/vutils"), interpolate_1 = require("../color-string/interpolate"), color_string_1 = require("../color-string"), config_1 = require("./config"), utils_1 = require("../common/utils"), enums_1 = require("../common/enums"), interpolateOtherAttrs = (attrs, out, ratio) => {
attrs.forEach((entry => {
if (Number.isFinite(entry.to)) out[entry.key] = entry.from + (entry.to - entry.from) * ratio; else if ("fill" === entry.key || "stroke" === entry.key) {
const color = (0, interpolate_1.interpolateColor)(entry.from, entry.to, ratio, !1);
color && (out[entry.key] = color);
}
}));
}, interpolateMorphingData = (morphingData, path, ratio) => {
const tmpArr = [], newCp = [];
path.clear();
for (let i = 0; i < morphingData.length; i++) {
const item = morphingData[i], from = item.from, to = item.to, angle = item.rotation * ratio, fromCp = item.fromCp, toCp = item.toCp, sa = Math.sin(angle), ca = Math.cos(angle);
newCp[0] = fromCp[0] + (toCp[0] - fromCp[0]) * ratio, newCp[1] = fromCp[1] + (toCp[1] - fromCp[1]) * ratio;
for (let m = 0; m < from.length; m += 2) {
const x0 = from[m], y0 = from[m + 1], x = x0 * (1 - ratio) + to[m] * ratio, y = y0 * (1 - ratio) + to[m + 1] * ratio;
tmpArr[m] = x * ca - y * sa + newCp[0], tmpArr[m + 1] = x * sa + y * ca + newCp[1];
}
let x0 = tmpArr[0], y0 = tmpArr[1];
path.moveTo(x0, y0);
for (let m = 2; m < from.length; m += 6) {
const x1 = tmpArr[m], y1 = tmpArr[m + 1], x2 = tmpArr[m + 2], y2 = tmpArr[m + 3], x3 = tmpArr[m + 4], y3 = tmpArr[m + 5];
x0 === x1 && y0 === y1 && x2 === x3 && y2 === y3 ? path.lineTo(x3, y3) : path.bezierCurveTo(x1, y1, x2, y2, x3, y3),
x0 = x3, y0 = y3;
}
}
}, parseMorphingData = (fromPath, toPath, config) => {
const fromBezier = fromPath ? (0, morphing_utils_1.pathToBezierCurves)(fromPath) : [], toBezier = (0,
morphing_utils_1.pathToBezierCurves)(toPath);
config && fromBezier && (config.fromTransform && (0, morphing_utils_1.applyTransformOnBezierCurves)(fromBezier, config.fromTransform.clone().getInverse()),
(0, morphing_utils_1.applyTransformOnBezierCurves)(fromBezier, config.toTransfrom));
const [fromBezierCurves, toBezierCurves] = (0, morphing_utils_1.alignBezierCurves)(fromBezier, toBezier);
return fromPath ? (0, morphing_utils_1.findBestMorphingRotation)(fromBezierCurves, toBezierCurves, 10, Math.PI) : toBezierCurves.map(((to, index) => ({
from: fromBezierCurves[index],
to: to,
fromCp: [ 0, 0 ],
toCp: [ 0, 0 ],
rotation: 0
})));
}, validateOtherAttrs = [ "fill", "fillOpacity", "shadowBlur", "shadowColor", "shadowOffsetX", "shadowOffsetY", "stroke", "strokeOpacity", "lineDashOffset" ], parseOtherAnimateAttrs = (fromAttrs, toAttrs) => {
if (!fromAttrs || !toAttrs) return null;
const res = [];
let hasAttr = !1;
return Object.keys(fromAttrs).forEach((fromKey => {
if (!validateOtherAttrs.includes(fromKey)) return;
const toValue = toAttrs[fromKey];
(0, vutils_1.isNil)(toValue) || (0, vutils_1.isNil)(fromAttrs[fromKey]) || toValue === fromAttrs[fromKey] || ("fill" === fromKey || "stroke" === fromKey ? res.push({
from: "string" == typeof fromAttrs[fromKey] ? color_string_1.ColorStore.Get(fromAttrs[fromKey], color_string_1.ColorType.Color255) : fromAttrs[fromKey],
to: "string" == typeof toValue ? color_string_1.ColorStore.Get(toValue, color_string_1.ColorType.Color255) : toValue,
key: fromKey
}) : res.push({
from: fromAttrs[fromKey],
to: toValue,
key: fromKey
}), hasAttr = !0);
})), hasAttr ? res : null;
};
class MorphingPath extends animate_1.ACustomAnimate {
constructor(config, duration, easing) {
super(0, 1, duration, easing), this.morphingData = config.morphingData, this.otherAttrs = config.otherAttrs,
this.saveOnEnd = config.saveOnEnd;
}
getEndProps() {
return {};
}
onBind() {
this.target.createPathProxy(), this.onUpdate(!1, 0, this.target.attribute);
}
onEnd() {}
onUpdate(end, ratio, out) {
const target = this.target, pathProxy = "function" == typeof target.pathProxy ? target.pathProxy(target.attribute) : target.pathProxy;
interpolateMorphingData(this.morphingData, pathProxy, ratio), this.otherAttrs && this.otherAttrs.length && interpolateOtherAttrs(this.otherAttrs, out, ratio),
end && !this.saveOnEnd && (this.target.pathProxy = null);
}
}
exports.MorphingPath = MorphingPath;
const morphPath = (fromGraphic, toGraphic, animationConfig, fromGraphicTransform) => {
var _a, _b, _c;
if (fromGraphic && (!fromGraphic.valid || !fromGraphic.toCustomPath)) return __DEV__ && console.error(fromGraphic, " is not validate"),
null;
if (!toGraphic.valid || !toGraphic.toCustomPath) return __DEV__ && console.error(toGraphic, " is not validate"),
null;
let fromTransform = null == fromGraphic ? void 0 : fromGraphic.globalTransMatrix;
fromGraphicTransform && fromTransform && (fromTransform = fromGraphicTransform.clone().multiply(fromTransform.a, fromTransform.b, fromTransform.c, fromTransform.d, fromTransform.e, fromTransform.f));
const morphingData = parseMorphingData(null === (_a = null == fromGraphic ? void 0 : fromGraphic.toCustomPath) || void 0 === _a ? void 0 : _a.call(fromGraphic), toGraphic.toCustomPath(), {
fromTransform: fromTransform,
toTransfrom: toGraphic.globalTransMatrix
}), attrs = parseOtherAnimateAttrs(null == fromGraphic ? void 0 : fromGraphic.attribute, toGraphic.attribute), animate = toGraphic.animate(animationConfig);
return (null == animationConfig ? void 0 : animationConfig.delay) && animate.wait(animationConfig.delay),
animate.play(new MorphingPath({
morphingData: morphingData,
otherAttrs: attrs
}, null !== (_b = null == animationConfig ? void 0 : animationConfig.duration) && void 0 !== _b ? _b : config_1.DefaultMorphingAnimateConfig.duration, null !== (_c = null == animationConfig ? void 0 : animationConfig.easing) && void 0 !== _c ? _c : config_1.DefaultMorphingAnimateConfig.easing)),
animate;
};
exports.morphPath = morphPath;
const oneToMultiMorph = (fromGraphic, toGraphics, animationConfig) => {
var _a;
const validateToGraphics = toGraphics.filter((graphic => graphic && graphic.toCustomPath && graphic.valid));
validateToGraphics.length || __DEV__ && console.error(validateToGraphics, " is not validate"),
fromGraphic.valid && fromGraphic.toCustomPath || __DEV__ && console.error(fromGraphic, " is not validate");
const childGraphics = ("clone" === (null == animationConfig ? void 0 : animationConfig.splitPath) ? exports.cloneGraphic : null !== (_a = null == animationConfig ? void 0 : animationConfig.splitPath) && void 0 !== _a ? _a : exports.splitGraphic)(fromGraphic, validateToGraphics.length, !1), oldOnEnd = null == animationConfig ? void 0 : animationConfig.onEnd;
let count = validateToGraphics.length;
const onEachEnd = () => {
count--, 0 === count && oldOnEnd && oldOnEnd();
};
validateToGraphics.forEach(((toChild, index) => {
var _a;
const fromChild = childGraphics[index], delay = (null !== (_a = null == animationConfig ? void 0 : animationConfig.delay) && void 0 !== _a ? _a : 0) + ((null == animationConfig ? void 0 : animationConfig.individualDelay) ? animationConfig.individualDelay(index, validateToGraphics.length, fromChild, toChild) : 0);
(0, exports.morphPath)(fromChild, toChild, Object.assign({}, animationConfig, {
onEnd: onEachEnd,
delay: delay
}), fromGraphic.globalTransMatrix);
}));
};
exports.oneToMultiMorph = oneToMultiMorph;
class MultiToOneMorphingPath extends animate_1.ACustomAnimate {
constructor(config, duration, easing) {
super(0, 1, duration, easing), this.morphingData = config.morphingData, this.otherAttrs = config.otherAttrs;
}
getEndProps() {
return {};
}
onBind() {
this.addPathProxy();
}
addPathProxy() {
this.target.shadowRoot.forEachChildren((child => {
child.createPathProxy();
})), this.onUpdate(!1, 0, this.target.attribute);
}
clearPathProxy() {
this.target.shadowRoot.forEachChildren((child => {
child.pathProxy = null;
}));
}
onEnd() {}
onUpdate(end, ratio, out) {
this.target.shadowRoot.forEachChildren(((child, index) => {
var _a;
interpolateMorphingData(this.morphingData[index], "function" == typeof child.pathProxy ? child.pathProxy(child.attribute) : child.pathProxy, ratio),
(null === (_a = this.otherAttrs) || void 0 === _a ? void 0 : _a[index]) && this.otherAttrs[index].length && interpolateOtherAttrs(this.otherAttrs[index], child.attribute, ratio);
})), end && (this.clearPathProxy(), this.morphingData = null);
}
}
exports.MultiToOneMorphingPath = MultiToOneMorphingPath;
const parseShadowChildAttrs = graphicAttrs => {
const attrs = {};
return Object.keys(graphicAttrs).forEach((key => {
(0, utils_1.isTransformKey)(key) || (attrs[key] = graphicAttrs[key]);
})), attrs;
}, appendShadowChildrenToGraphic = (graphic, children, count) => {
const childAttrs = parseShadowChildAttrs(graphic.attribute), shadowRoot = graphic.attachShadow();
if (children.length) shadowRoot.setTheme({
[children[0].type]: childAttrs
}), children.forEach((element => {
element.setAttributes({
pickable: !1
}), shadowRoot.appendChild(element);
})); else {
const box = graphic.AABBBounds, width = box.width(), height = box.height();
shadowRoot.setTheme({
rect: childAttrs
}), new Array(count).fill(0).forEach((el => {
const child = application_1.application.graphicService.creator.rect({
x: 0,
y: 0,
width: width,
height: height,
pickable: !1
});
shadowRoot.appendChild(child), children.push(child);
}));
}
}, cloneGraphic = (graphic, count, needAppend) => {
const children = [], childAttrs = needAppend ? null : parseShadowChildAttrs(graphic.attribute), path = graphic.toCustomPath();
for (let i = 0; i < count; i++) {
const element = {
path: (new custom_path2d_1.CustomPath2D).fromCustomPath2D(path)
};
children.push(application_1.application.graphicService.creator.path(needAppend ? element : Object.assign({}, childAttrs, element)));
}
return needAppend && appendShadowChildrenToGraphic(graphic, children, count), children;
};
exports.cloneGraphic = cloneGraphic;
const splitGraphic = (graphic, count, needAppend) => {
const children = [], childAttrs = needAppend ? null : parseShadowChildAttrs(graphic.attribute);
if ("rect" === graphic.type) {
(0, split_path_1.splitRect)(graphic, count).forEach((element => {
children.push(application_1.application.graphicService.creator.rect(needAppend ? element : Object.assign({}, childAttrs, element)));
}));
} else if ("arc" === graphic.type) {
(0, split_path_1.splitArc)(graphic, count).forEach((element => {
children.push(application_1.application.graphicService.creator.arc(needAppend ? element : Object.assign({}, childAttrs, element)));
}));
} else if ("circle" === graphic.type) {
(0, split_path_1.splitCircle)(graphic, count).forEach((element => {
children.push(application_1.application.graphicService.creator.arc(needAppend ? element : Object.assign({}, childAttrs, element)));
}));
} else if ("line" === graphic.type) {
const childrenAttrs = (0, split_path_1.splitLine)(graphic, count), defaultSymbol = {
size: 10,
symbolType: "circle"
};
childrenAttrs.forEach((element => {
children.push(application_1.application.graphicService.creator.symbol(needAppend ? Object.assign({}, element, defaultSymbol) : Object.assign({}, childAttrs, element, defaultSymbol)));
}));
} else if ("polygon" === graphic.type) {
(0, split_path_1.splitPolygon)(graphic, count).forEach((element => {
children.push(application_1.application.graphicService.creator.polygon(needAppend ? element : Object.assign({}, childAttrs, element)));
}));
} else if ("area" === graphic.type) {
(0, split_path_1.splitArea)(graphic, count).forEach((element => {
children.push(application_1.application.graphicService.creator.polygon(needAppend ? element : Object.assign({}, childAttrs, element)));
}));
} else if ("path" === graphic.type) {
(0, split_path_1.splitPath)(graphic, count).forEach((element => {
"path" in element ? children.push(application_1.application.graphicService.creator.path(needAppend ? element : Object.assign({}, childAttrs, element))) : children.push(application_1.application.graphicService.creator.polygon(needAppend ? element : Object.assign({}, childAttrs, element)));
}));
}
return needAppend && appendShadowChildrenToGraphic(graphic, children, count), children;
};
exports.splitGraphic = splitGraphic;
const multiToOneMorph = (fromGraphics, toGraphic, animationConfig) => {
var _a, _b, _c;
const validateFromGraphics = fromGraphics.filter((graphic => graphic.toCustomPath && graphic.valid));
validateFromGraphics.length || __DEV__ && console.error(fromGraphics, " is not validate"),
toGraphic.valid && toGraphic.toCustomPath || __DEV__ && console.error(toGraphic, " is not validate");
const childGraphics = ("clone" === (null == animationConfig ? void 0 : animationConfig.splitPath) ? exports.cloneGraphic : null !== (_a = null == animationConfig ? void 0 : animationConfig.splitPath) && void 0 !== _a ? _a : exports.splitGraphic)(toGraphic, validateFromGraphics.length, !0), toAttrs = toGraphic.attribute;
toGraphic.setAttribute("visible", !1);
const morphingData = validateFromGraphics.map(((graphic, index) => parseMorphingData(graphic.toCustomPath(), childGraphics[index].toCustomPath(), {
fromTransform: graphic.globalTransMatrix,
toTransfrom: childGraphics[index].globalTransMatrix
}))), otherAttrs = validateFromGraphics.map(((graphic, index) => parseOtherAnimateAttrs(graphic.attribute, toAttrs)));
if (null == animationConfig ? void 0 : animationConfig.individualDelay) {
const oldOnEnd = animationConfig.onEnd;
let count = validateFromGraphics.length;
const onEachEnd = () => {
count--, 0 === count && (toGraphic.setAttributes({
visible: !0,
ratio: null
}, !1, {
type: enums_1.AttributeUpdateType.ANIMATE_END
}), toGraphic.detachShadow(), oldOnEnd && oldOnEnd());
};
childGraphics.forEach(((to, index) => {
var _a, _b, _c;
const delay = (null !== (_a = animationConfig.delay) && void 0 !== _a ? _a : 0) + animationConfig.individualDelay(index, validateFromGraphics.length, fromGraphics[index], to), animate = to.animate(Object.assign({}, animationConfig, {
onEnd: onEachEnd
}));
animate.wait(delay), animate.play(new MorphingPath({
morphingData: morphingData[index],
saveOnEnd: !0,
otherAttrs: otherAttrs[index]
}, null !== (_b = animationConfig.duration) && void 0 !== _b ? _b : config_1.DefaultMorphingAnimateConfig.duration, null !== (_c = animationConfig.easing) && void 0 !== _c ? _c : config_1.DefaultMorphingAnimateConfig.easing));
}));
} else {
const oldOnEnd = null == animationConfig ? void 0 : animationConfig.onEnd, config = animationConfig ? Object.assign({}, animationConfig) : {};
config.onEnd = () => {
toGraphic.setAttribute("visible", !0, !1, {
type: enums_1.AttributeUpdateType.ANIMATE_END
}), toGraphic.detachShadow(), oldOnEnd && oldOnEnd();
};
const animate = toGraphic.animate(config);
(null == animationConfig ? void 0 : animationConfig.delay) && animate.wait(animationConfig.delay),
animate.play(new MultiToOneMorphingPath({
morphingData: morphingData,
otherAttrs: otherAttrs
}, null !== (_b = null == animationConfig ? void 0 : animationConfig.duration) && void 0 !== _b ? _b : config_1.DefaultMorphingAnimateConfig.duration, null !== (_c = null == animationConfig ? void 0 : animationConfig.easing) && void 0 !== _c ? _c : config_1.DefaultMorphingAnimateConfig.easing));
}
};
exports.multiToOneMorph = multiToOneMorph;
//# sourceMappingURL=morphing.js.map