@leafer-in/motion-path 1.0.6-rc1

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.
@@ -0,0 +1,321 @@
1
+ this.LeaferIN = this.LeaferIN || {};
2
+ this.LeaferIN.motionPath = (function (exports, draw) {
3
+ 'use strict';
4
+
5
+ const gaussNodes = [0.1488743389, 0.4333953941, 0.6794095682, 0.8650633666, 0.9739065285];
6
+ const gaussWeights = [0.2955242247, 0.2692667193, 0.2190863625, 0.1494513491, 0.0666713443];
7
+ const { sqrt } = Math;
8
+ const HighBezierHelper = {
9
+ getDistance(fromX, fromY, x1, y1, x2, y2, toX, toY) {
10
+ let distance = 0, t1, t2, d1X, d1Y, d2X, d2Y;
11
+ for (let i = 0; i < gaussNodes.length; i++) {
12
+ t1 = 0.5 * (1 + gaussNodes[i]);
13
+ t2 = 0.5 * (1 - gaussNodes[i]);
14
+ d1X = getDerivative(t1, fromX, x1, x2, toX);
15
+ d1Y = getDerivative(t1, fromY, y1, y2, toY);
16
+ d2X = getDerivative(t2, fromX, x1, x2, toX);
17
+ d2Y = getDerivative(t2, fromY, y1, y2, toY);
18
+ distance += gaussWeights[i] * (sqrt(d1X * d1X + d1Y * d1Y) + sqrt(d2X * d2X + d2Y * d2Y));
19
+ }
20
+ return distance * 0.5;
21
+ },
22
+ getDerivative(t, fromV, v1, v2, toV) {
23
+ const o = 1 - t;
24
+ return 3 * o * o * (v1 - fromV) + 6 * o * t * (v2 - v1) + 3 * t * t * (toV - v2);
25
+ },
26
+ cut(data, t, fromX, fromY, x1, y1, x2, y2, toX, toY) {
27
+ const o = 1 - t;
28
+ const ax = o * fromX + t * x1, ay = o * fromY + t * y1;
29
+ const mbx = o * x1 + t * x2, mby = o * y1 + t * y2;
30
+ const mcx = o * x2 + t * toX, mcy = o * y2 + t * toY;
31
+ const bx = o * ax + t * mbx, by = o * ay + t * mby;
32
+ const mbcx = o * mbx + t * mcx, mbcy = o * mby + t * mcy;
33
+ const cx = o * bx + t * mbcx, cy = o * by + t * mbcy;
34
+ data.push(draw.PathCommandMap.C, ax, ay, bx, by, cx, cy);
35
+ }
36
+ };
37
+ const { getDerivative } = HighBezierHelper;
38
+
39
+ const { M, L, C, Z } = draw.PathCommandMap;
40
+ const tempPoint = {}, tempFrom = {};
41
+ const HighCurveHelper = {
42
+ transform(data, matrix) {
43
+ let i = 0, command;
44
+ const len = data.length;
45
+ while (i < len) {
46
+ command = data[i];
47
+ switch (command) {
48
+ case M:
49
+ case L:
50
+ HighCurveHelper.transformPoints(data, matrix, i, 1);
51
+ i += 3;
52
+ break;
53
+ case C:
54
+ HighCurveHelper.transformPoints(data, matrix, i, 3);
55
+ i += 7;
56
+ break;
57
+ case Z:
58
+ i += 1;
59
+ }
60
+ }
61
+ },
62
+ transformPoints(data, matrix, start, pointCount) {
63
+ for (let i = start + 1, end = i + pointCount * 2; i < end; i += 2) {
64
+ tempPoint.x = data[i];
65
+ tempPoint.y = data[i + 1];
66
+ draw.MatrixHelper.toOuterPoint(matrix, tempPoint);
67
+ data[i] = tempPoint.x;
68
+ data[i + 1] = tempPoint.y;
69
+ }
70
+ },
71
+ getMotionPathData(data) {
72
+ let total = 0, distance, segments = [];
73
+ let i = 0, x = 0, y = 0, toX, toY, command;
74
+ const len = data.length;
75
+ while (i < len) {
76
+ command = data[i];
77
+ switch (command) {
78
+ case M:
79
+ case L:
80
+ toX = data[i + 1];
81
+ toY = data[i + 2];
82
+ distance = (command === L && i > 0) ? draw.PointHelper.getDistanceFrom(x, y, toX, toY) : 0;
83
+ x = toX;
84
+ y = toY;
85
+ i += 3;
86
+ break;
87
+ case C:
88
+ toX = data[i + 5];
89
+ toY = data[i + 6];
90
+ distance = HighBezierHelper.getDistance(x, y, data[i + 1], data[i + 2], data[i + 3], data[i + 4], toX, toY);
91
+ x = toX;
92
+ y = toY;
93
+ i += 7;
94
+ break;
95
+ case Z:
96
+ i += 1;
97
+ default:
98
+ distance = 0;
99
+ }
100
+ segments.push(distance);
101
+ total += distance;
102
+ }
103
+ return { total, segments, data };
104
+ },
105
+ getDistancePoint(distanceData, motionDistance) {
106
+ const { segments, data } = distanceData;
107
+ motionDistance = draw.UnitConvert.number(motionDistance, distanceData.total);
108
+ let total = 0, distance, to = {};
109
+ let i = 0, index = 0, x = 0, y = 0, toX, toY, command;
110
+ const len = data.length;
111
+ while (i < len) {
112
+ command = data[i];
113
+ switch (command) {
114
+ case M:
115
+ case L:
116
+ toX = data[i + 1];
117
+ toY = data[i + 2];
118
+ distance = segments[index];
119
+ if (total + distance > motionDistance || !distanceData.total) {
120
+ if (!i)
121
+ x = toX, y = toY;
122
+ tempFrom.x = x;
123
+ tempFrom.y = y;
124
+ to.x = toX;
125
+ to.y = toY;
126
+ draw.PointHelper.getDistancePoint(tempFrom, to, motionDistance - total, true);
127
+ to.rotation = draw.PointHelper.getAngle(tempFrom, to);
128
+ return to;
129
+ }
130
+ x = toX;
131
+ y = toY;
132
+ i += 3;
133
+ break;
134
+ case C:
135
+ toX = data[i + 5];
136
+ toY = data[i + 6];
137
+ distance = segments[index];
138
+ if (total + distance > motionDistance) {
139
+ const x1 = data[i + 1], y1 = data[i + 2], x2 = data[i + 3], y2 = data[i + 4];
140
+ motionDistance -= total;
141
+ draw.BezierHelper.getPointAndSet(motionDistance / distance, x, y, x1, y1, x2, y2, toX, toY, to);
142
+ draw.BezierHelper.getPointAndSet(Math.max(0, motionDistance - 0.1) / distance, x, y, x1, y1, x2, y2, toX, toY, tempFrom);
143
+ to.rotation = draw.PointHelper.getAngle(tempFrom, to);
144
+ return to;
145
+ }
146
+ x = toX;
147
+ y = toY;
148
+ i += 7;
149
+ break;
150
+ case Z:
151
+ i += 1;
152
+ default:
153
+ distance = 0;
154
+ }
155
+ index++;
156
+ total += distance;
157
+ }
158
+ return to;
159
+ },
160
+ getDistancePath(distanceData, motionDistance) {
161
+ const { segments, data } = distanceData, path = [];
162
+ motionDistance = draw.UnitConvert.number(motionDistance, distanceData.total);
163
+ let total = 0, distance, to = {};
164
+ let i = 0, index = 0, x = 0, y = 0, toX, toY, command;
165
+ const len = data.length;
166
+ while (i < len) {
167
+ command = data[i];
168
+ switch (command) {
169
+ case M:
170
+ case L:
171
+ toX = data[i + 1];
172
+ toY = data[i + 2];
173
+ distance = segments[index];
174
+ if (total + distance > motionDistance || !distanceData.total) {
175
+ if (!i)
176
+ x = toX, y = toY;
177
+ tempFrom.x = x;
178
+ tempFrom.y = y;
179
+ to.x = toX;
180
+ to.y = toY;
181
+ draw.PointHelper.getDistancePoint(tempFrom, to, motionDistance - total, true);
182
+ path.push(command, to.x, to.y);
183
+ return path;
184
+ }
185
+ x = toX;
186
+ y = toY;
187
+ i += 3;
188
+ path.push(command, x, y);
189
+ break;
190
+ case C:
191
+ const x1 = data[i + 1], y1 = data[i + 2], x2 = data[i + 3], y2 = data[i + 4];
192
+ toX = data[i + 5];
193
+ toY = data[i + 6];
194
+ distance = segments[index];
195
+ if (total + distance > motionDistance) {
196
+ HighBezierHelper.cut(path, (motionDistance - total) / distance, x, y, x1, y1, x2, y2, toX, toY);
197
+ return path;
198
+ }
199
+ x = toX;
200
+ y = toY;
201
+ i += 7;
202
+ path.push(command, x1, y1, x2, y2, toX, toY);
203
+ break;
204
+ case Z:
205
+ i += 1;
206
+ path.push(command);
207
+ default:
208
+ distance = 0;
209
+ }
210
+ index++;
211
+ total += distance;
212
+ }
213
+ return path;
214
+ }
215
+ };
216
+
217
+ function motionPathType(defaultValue) {
218
+ return draw.decorateLeafAttr(defaultValue, (key) => draw.attr({
219
+ set(value) {
220
+ this.__setAttr(key, value);
221
+ this.__hasMotionPath = this.motionPath || !draw.isNull(this.motion);
222
+ this.__layout.matrixChanged || this.__layout.matrixChange();
223
+ }
224
+ }));
225
+ }
226
+
227
+ draw.Transition.register('motion', function (from, to, t, target) {
228
+ if (!from)
229
+ from = 0;
230
+ else if (typeof from === 'object')
231
+ from = draw.UnitConvert.number(from, target.getMotionTotal());
232
+ if (!to)
233
+ to = 0;
234
+ else if (typeof to === 'object')
235
+ to = draw.UnitConvert.number(to, target.getMotionTotal());
236
+ return draw.Transition.number(from, to, t);
237
+ });
238
+ const ui = draw.UI.prototype;
239
+ motionPathType()(ui, 'motionPath');
240
+ motionPathType()(ui, 'motion');
241
+ motionPathType(true)(ui, 'motionRotation');
242
+ ui.getMotionPathData = function () {
243
+ const { parent } = this;
244
+ if (!this.motionPath && parent) {
245
+ const { children } = parent;
246
+ for (let i = 0; i < children.length; i++) {
247
+ if (children[i].motionPath)
248
+ return children[i].getMotionPathData();
249
+ }
250
+ }
251
+ const data = this.__;
252
+ if (data.__pathForMotion)
253
+ return data.__pathForMotion;
254
+ return data.__pathForMotion = HighCurveHelper.getMotionPathData(this.getPath(true, true));
255
+ };
256
+ ui.getMotionPoint = function (motionDistance) {
257
+ const data = this.getMotionPathData();
258
+ const point = HighCurveHelper.getDistancePoint(data, motionDistance);
259
+ draw.MatrixHelper.toOuterPoint(this.localTransform, point);
260
+ return point;
261
+ };
262
+ ui.getMotionTotal = function () {
263
+ return this.getMotionPathData().total;
264
+ };
265
+ ui.__updateMotionPath = function () {
266
+ const data = this.__;
267
+ if (this.__layout.resized && data.__pathForMotion)
268
+ data.__pathForMotion = undefined;
269
+ if (this.motionPath) {
270
+ let child;
271
+ const { children } = this.parent;
272
+ for (let i = 0; i < children.length; i++) {
273
+ child = children[i];
274
+ if (!draw.isNull(child.motion))
275
+ updateMotion(child);
276
+ }
277
+ }
278
+ else {
279
+ updateMotion(this);
280
+ }
281
+ };
282
+ function updateMotion(leaf) {
283
+ const { motion, motionRotation } = leaf;
284
+ if (draw.isNull(motion))
285
+ return;
286
+ if (leaf.motionPath) {
287
+ const data = leaf.getMotionPathData();
288
+ if (data.total)
289
+ leaf.__.__pathForRender = HighCurveHelper.getDistancePath(data, motion);
290
+ }
291
+ else {
292
+ let child;
293
+ const { children } = leaf.parent;
294
+ for (let i = 0; i < children.length; i++) {
295
+ child = children[i];
296
+ if (child.motionPath) {
297
+ const data = child.getMotionPathData();
298
+ if (!data.total)
299
+ return;
300
+ const point = child.getMotionPoint(motion);
301
+ if (motionRotation === false)
302
+ delete point.rotation;
303
+ else {
304
+ point.rotation += child.rotation;
305
+ if (typeof motionRotation === 'number')
306
+ point.rotation += motionRotation;
307
+ }
308
+ leaf.set(point);
309
+ break;
310
+ }
311
+ }
312
+ }
313
+ }
314
+
315
+ exports.HighBezierHelper = HighBezierHelper;
316
+ exports.HighCurveHelper = HighCurveHelper;
317
+ exports.motionPathType = motionPathType;
318
+
319
+ return exports;
320
+
321
+ })({}, LeaferUI);
@@ -0,0 +1 @@
1
+ "use strict";var t=require("@leafer-ui/draw");const e=[.1488743389,.4333953941,.6794095682,.8650633666,.9739065285],o=[.2955242247,.2692667193,.2190863625,.1494513491,.0666713443],{sqrt:n}=Math,a={getDistance(t,a,r,s,h,c,l,u){let g,P,f,p,m,_,M=0;for(let d=0;d<e.length;d++)g=.5*(1+e[d]),P=.5*(1-e[d]),f=i(g,t,r,h,l),p=i(g,a,s,c,u),m=i(P,t,r,h,l),_=i(P,a,s,c,u),M+=o[d]*(n(f*f+p*p)+n(m*m+_*_));return.5*M},getDerivative(t,e,o,n,a){const i=1-t;return 3*i*i*(o-e)+6*i*t*(n-o)+3*t*t*(a-n)},cut(e,o,n,a,i,r,s,h,c,l){const u=1-o,g=u*n+o*i,P=u*a+o*r,f=u*i+o*s,p=u*r+o*h,m=u*g+o*f,_=u*P+o*p,M=u*m+o*(u*f+o*(u*s+o*c)),d=u*_+o*(u*p+o*(u*h+o*l));e.push(t.PathCommandMap.C,g,P,m,_,M,d)}},{getDerivative:i}=a,{M:r,L:s,C:h,Z:c}=t.PathCommandMap,l={},u={},g={transform(t,e){let o,n=0;const a=t.length;for(;n<a;)switch(o=t[n],o){case r:case s:g.transformPoints(t,e,n,1),n+=3;break;case h:g.transformPoints(t,e,n,3),n+=7;break;case c:n+=1}},transformPoints(e,o,n,a){for(let i=n+1,r=i+2*a;i<r;i+=2)l.x=e[i],l.y=e[i+1],t.MatrixHelper.toOuterPoint(o,l),e[i]=l.x,e[i+1]=l.y},getMotionPathData(e){let o,n,i,l,u=0,g=[],P=0,f=0,p=0;const m=e.length;for(;P<m;){switch(l=e[P],l){case r:case s:n=e[P+1],i=e[P+2],o=l===s&&P>0?t.PointHelper.getDistanceFrom(f,p,n,i):0,f=n,p=i,P+=3;break;case h:n=e[P+5],i=e[P+6],o=a.getDistance(f,p,e[P+1],e[P+2],e[P+3],e[P+4],n,i),f=n,p=i,P+=7;break;case c:P+=1;default:o=0}g.push(o),u+=o}return{total:u,segments:g,data:e}},getDistancePoint(e,o){const{segments:n,data:a}=e;o=t.UnitConvert.number(o,e.total);let i,l,g,P,f=0,p={},m=0,_=0,M=0,d=0;const D=a.length;for(;m<D;){switch(P=a[m],P){case r:case s:if(l=a[m+1],g=a[m+2],i=n[_],f+i>o||!e.total)return m||(M=l,d=g),u.x=M,u.y=d,p.x=l,p.y=g,t.PointHelper.getDistancePoint(u,p,o-f,!0),p.rotation=t.PointHelper.getAngle(u,p),p;M=l,d=g,m+=3;break;case h:if(l=a[m+5],g=a[m+6],i=n[_],f+i>o){const e=a[m+1],n=a[m+2],r=a[m+3],s=a[m+4];return o-=f,t.BezierHelper.getPointAndSet(o/i,M,d,e,n,r,s,l,g,p),t.BezierHelper.getPointAndSet(Math.max(0,o-.1)/i,M,d,e,n,r,s,l,g,u),p.rotation=t.PointHelper.getAngle(u,p),p}M=l,d=g,m+=7;break;case c:m+=1;default:i=0}_++,f+=i}return p},getDistancePath(e,o){const{segments:n,data:i}=e,l=[];o=t.UnitConvert.number(o,e.total);let g,P,f,p,m=0,_={},M=0,d=0,D=0,b=0;const x=i.length;for(;M<x;){switch(p=i[M],p){case r:case s:if(P=i[M+1],f=i[M+2],g=n[d],m+g>o||!e.total)return M||(D=P,b=f),u.x=D,u.y=b,_.x=P,_.y=f,t.PointHelper.getDistancePoint(u,_,o-m,!0),l.push(p,_.x,_.y),l;D=P,b=f,M+=3,l.push(p,D,b);break;case h:const x=i[M+1],y=i[M+2],H=i[M+3],v=i[M+4];if(P=i[M+5],f=i[M+6],g=n[d],m+g>o)return a.cut(l,(o-m)/g,D,b,x,y,H,v,P,f),l;D=P,b=f,M+=7,l.push(p,x,y,H,v,P,f);break;case c:M+=1,l.push(p);default:g=0}d++,m+=g}return l}};function P(e){return t.decorateLeafAttr(e,(e=>t.attr({set(o){this.__setAttr(e,o),this.__hasMotionPath=this.motionPath||!t.isNull(this.motion),this.__layout.matrixChanged||this.__layout.matrixChange()}})))}t.Transition.register("motion",(function(e,o,n,a){return e?"object"==typeof e&&(e=t.UnitConvert.number(e,a.getMotionTotal())):e=0,o?"object"==typeof o&&(o=t.UnitConvert.number(o,a.getMotionTotal())):o=0,t.Transition.number(e,o,n)}));const f=t.UI.prototype;function p(e){const{motion:o,motionRotation:n}=e;if(!t.isNull(o))if(e.motionPath){const t=e.getMotionPathData();t.total&&(e.__.__pathForRender=g.getDistancePath(t,o))}else{let t;const{children:a}=e.parent;for(let i=0;i<a.length;i++)if(t=a[i],t.motionPath){if(!t.getMotionPathData().total)return;const a=t.getMotionPoint(o);!1===n?delete a.rotation:(a.rotation+=t.rotation,"number"==typeof n&&(a.rotation+=n)),e.set(a);break}}}P()(f,"motionPath"),P()(f,"motion"),P(!0)(f,"motionRotation"),f.getMotionPathData=function(){const{parent:t}=this;if(!this.motionPath&&t){const{children:e}=t;for(let t=0;t<e.length;t++)if(e[t].motionPath)return e[t].getMotionPathData()}const e=this.__;return e.__pathForMotion?e.__pathForMotion:e.__pathForMotion=g.getMotionPathData(this.getPath(!0,!0))},f.getMotionPoint=function(e){const o=this.getMotionPathData(),n=g.getDistancePoint(o,e);return t.MatrixHelper.toOuterPoint(this.localTransform,n),n},f.getMotionTotal=function(){return this.getMotionPathData().total},f.__updateMotionPath=function(){const e=this.__;if(this.__layout.resized&&e.__pathForMotion&&(e.__pathForMotion=void 0),this.motionPath){let e;const{children:o}=this.parent;for(let n=0;n<o.length;n++)e=o[n],t.isNull(e.motion)||p(e)}else p(this)},exports.HighBezierHelper=a,exports.HighCurveHelper=g,exports.motionPathType=P;
@@ -0,0 +1 @@
1
+ this.LeaferIN=this.LeaferIN||{},this.LeaferIN.motionPath=function(t,e){"use strict";const o=[.1488743389,.4333953941,.6794095682,.8650633666,.9739065285],n=[.2955242247,.2692667193,.2190863625,.1494513491,.0666713443],{sqrt:a}=Math,i={getDistance(t,e,i,s,h,c,l,u){let g,f,P,m,p,_,M=0;for(let d=0;d<o.length;d++)g=.5*(1+o[d]),f=.5*(1-o[d]),P=r(g,t,i,h,l),m=r(g,e,s,c,u),p=r(f,t,i,h,l),_=r(f,e,s,c,u),M+=n[d]*(a(P*P+m*m)+a(p*p+_*_));return.5*M},getDerivative(t,e,o,n,a){const i=1-t;return 3*i*i*(o-e)+6*i*t*(n-o)+3*t*t*(a-n)},cut(t,o,n,a,i,r,s,h,c,l){const u=1-o,g=u*n+o*i,f=u*a+o*r,P=u*i+o*s,m=u*r+o*h,p=u*g+o*P,_=u*f+o*m,M=u*p+o*(u*P+o*(u*s+o*c)),d=u*_+o*(u*m+o*(u*h+o*l));t.push(e.PathCommandMap.C,g,f,p,_,M,d)}},{getDerivative:r}=i,{M:s,L:h,C:c,Z:l}=e.PathCommandMap,u={},g={},f={transform(t,e){let o,n=0;const a=t.length;for(;n<a;)switch(o=t[n],o){case s:case h:f.transformPoints(t,e,n,1),n+=3;break;case c:f.transformPoints(t,e,n,3),n+=7;break;case l:n+=1}},transformPoints(t,o,n,a){for(let i=n+1,r=i+2*a;i<r;i+=2)u.x=t[i],u.y=t[i+1],e.MatrixHelper.toOuterPoint(o,u),t[i]=u.x,t[i+1]=u.y},getMotionPathData(t){let o,n,a,r,u=0,g=[],f=0,P=0,m=0;const p=t.length;for(;f<p;){switch(r=t[f],r){case s:case h:n=t[f+1],a=t[f+2],o=r===h&&f>0?e.PointHelper.getDistanceFrom(P,m,n,a):0,P=n,m=a,f+=3;break;case c:n=t[f+5],a=t[f+6],o=i.getDistance(P,m,t[f+1],t[f+2],t[f+3],t[f+4],n,a),P=n,m=a,f+=7;break;case l:f+=1;default:o=0}g.push(o),u+=o}return{total:u,segments:g,data:t}},getDistancePoint(t,o){const{segments:n,data:a}=t;o=e.UnitConvert.number(o,t.total);let i,r,u,f,P=0,m={},p=0,_=0,M=0,d=0;const D=a.length;for(;p<D;){switch(f=a[p],f){case s:case h:if(r=a[p+1],u=a[p+2],i=n[_],P+i>o||!t.total)return p||(M=r,d=u),g.x=M,g.y=d,m.x=r,m.y=u,e.PointHelper.getDistancePoint(g,m,o-P,!0),m.rotation=e.PointHelper.getAngle(g,m),m;M=r,d=u,p+=3;break;case c:if(r=a[p+5],u=a[p+6],i=n[_],P+i>o){const t=a[p+1],n=a[p+2],s=a[p+3],h=a[p+4];return o-=P,e.BezierHelper.getPointAndSet(o/i,M,d,t,n,s,h,r,u,m),e.BezierHelper.getPointAndSet(Math.max(0,o-.1)/i,M,d,t,n,s,h,r,u,g),m.rotation=e.PointHelper.getAngle(g,m),m}M=r,d=u,p+=7;break;case l:p+=1;default:i=0}_++,P+=i}return m},getDistancePath(t,o){const{segments:n,data:a}=t,r=[];o=e.UnitConvert.number(o,t.total);let u,f,P,m,p=0,_={},M=0,d=0,D=0,b=0;const y=a.length;for(;M<y;){switch(m=a[M],m){case s:case h:if(f=a[M+1],P=a[M+2],u=n[d],p+u>o||!t.total)return M||(D=f,b=P),g.x=D,g.y=b,_.x=f,_.y=P,e.PointHelper.getDistancePoint(g,_,o-p,!0),r.push(m,_.x,_.y),r;D=f,b=P,M+=3,r.push(m,D,b);break;case c:const y=a[M+1],H=a[M+2],x=a[M+3],C=a[M+4];if(f=a[M+5],P=a[M+6],u=n[d],p+u>o)return i.cut(r,(o-p)/u,D,b,y,H,x,C,f,P),r;D=f,b=P,M+=7,r.push(m,y,H,x,C,f,P);break;case l:M+=1,r.push(m);default:u=0}d++,p+=u}return r}};function P(t){return e.decorateLeafAttr(t,(t=>e.attr({set(o){this.__setAttr(t,o),this.__hasMotionPath=this.motionPath||!e.isNull(this.motion),this.__layout.matrixChanged||this.__layout.matrixChange()}})))}e.Transition.register("motion",(function(t,o,n,a){return t?"object"==typeof t&&(t=e.UnitConvert.number(t,a.getMotionTotal())):t=0,o?"object"==typeof o&&(o=e.UnitConvert.number(o,a.getMotionTotal())):o=0,e.Transition.number(t,o,n)}));const m=e.UI.prototype;function p(t){const{motion:o,motionRotation:n}=t;if(!e.isNull(o))if(t.motionPath){const e=t.getMotionPathData();e.total&&(t.__.__pathForRender=f.getDistancePath(e,o))}else{let e;const{children:a}=t.parent;for(let i=0;i<a.length;i++)if(e=a[i],e.motionPath){if(!e.getMotionPathData().total)return;const a=e.getMotionPoint(o);!1===n?delete a.rotation:(a.rotation+=e.rotation,"number"==typeof n&&(a.rotation+=n)),t.set(a);break}}}return P()(m,"motionPath"),P()(m,"motion"),P(!0)(m,"motionRotation"),m.getMotionPathData=function(){const{parent:t}=this;if(!this.motionPath&&t){const{children:e}=t;for(let t=0;t<e.length;t++)if(e[t].motionPath)return e[t].getMotionPathData()}const e=this.__;return e.__pathForMotion?e.__pathForMotion:e.__pathForMotion=f.getMotionPathData(this.getPath(!0,!0))},m.getMotionPoint=function(t){const o=this.getMotionPathData(),n=f.getDistancePoint(o,t);return e.MatrixHelper.toOuterPoint(this.localTransform,n),n},m.getMotionTotal=function(){return this.getMotionPathData().total},m.__updateMotionPath=function(){const t=this.__;if(this.__layout.resized&&t.__pathForMotion&&(t.__pathForMotion=void 0),this.motionPath){let t;const{children:o}=this.parent;for(let n=0;n<o.length;n++)t=o[n],e.isNull(t.motion)||p(t)}else p(this)},t.HighBezierHelper=i,t.HighCurveHelper=f,t.motionPathType=P,t}({},LeaferUI);
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@leafer-in/motion-path",
3
+ "version": "1.0.6-rc1",
4
+ "description": "@leafer-in/motion-path",
5
+ "author": "Chao (Leafer) Wan",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/motion-path.esm.js",
9
+ "exports": {
10
+ "import": "./dist/motion-path.esm.js",
11
+ "require": "./dist/motion-path.cjs",
12
+ "types": "./types/index.d.ts"
13
+ },
14
+ "types": "types/index.d.ts",
15
+ "unpkg": "dist/motion-path.js",
16
+ "jsdelivr": "dist/motion-path.js",
17
+ "files": ["src","types","dist"],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/leaferjs/leafer-in.git"
21
+ },
22
+ "homepage": "https://github.com/leaferjs/leafer-in/tree/main/packages/motion-path",
23
+ "bugs": "https://github.com/leaferjs/leafer-in/issues",
24
+ "keywords": [
25
+ "leafer motion path",
26
+ "leafer-motion-path",
27
+ "leafer-in",
28
+ "motion-path",
29
+ "leafer-ui",
30
+ "leaferjs"
31
+ ],
32
+ "dependencies": {
33
+ "@leafer-ui/draw": "^1.0.6",
34
+ "@leafer-ui/interface": "^1.0.6",
35
+ "@leafer-in/interface": "^1.0.6"
36
+ }
37
+ }
@@ -0,0 +1,50 @@
1
+ import { IPathCommandData } from '@leafer-ui/interface'
2
+ import { PathCommandMap } from '@leafer-ui/draw'
3
+
4
+
5
+ // 高斯-勒让德积分节点和权重
6
+ const gaussNodes = [0.1488743389, 0.4333953941, 0.6794095682, 0.8650633666, 0.9739065285]
7
+ const gaussWeights = [0.2955242247, 0.2692667193, 0.2190863625, 0.1494513491, 0.0666713443]
8
+
9
+ const { sqrt } = Math
10
+
11
+ export const HighBezierHelper = {
12
+
13
+ getDistance(fromX: number, fromY: number, x1: number, y1: number, x2: number, y2: number, toX: number, toY: number): number {
14
+ let distance = 0, t1: number, t2: number, d1X: number, d1Y: number, d2X: number, d2Y: number
15
+ for (let i = 0; i < gaussNodes.length; i++) {
16
+ t1 = 0.5 * (1 + gaussNodes[i])
17
+ t2 = 0.5 * (1 - gaussNodes[i])
18
+
19
+ d1X = getDerivative(t1, fromX, x1, x2, toX)
20
+ d1Y = getDerivative(t1, fromY, y1, y2, toY)
21
+
22
+ d2X = getDerivative(t2, fromX, x1, x2, toX)
23
+ d2Y = getDerivative(t2, fromY, y1, y2, toY)
24
+
25
+ distance += gaussWeights[i] * (sqrt(d1X * d1X + d1Y * d1Y) + sqrt(d2X * d2X + d2Y * d2Y))
26
+ }
27
+ return distance * 0.5
28
+ },
29
+
30
+ getDerivative(t: number, fromV: number, v1: number, v2: number, toV: number): number { // 导数
31
+ const o = 1 - t
32
+ return 3 * o * o * (v1 - fromV) + 6 * o * t * (v2 - v1) + 3 * t * t * (toV - v2)
33
+ },
34
+
35
+ cut(data: IPathCommandData, t: number, fromX: number, fromY: number, x1: number, y1: number, x2: number, y2: number, toX: number, toY: number) {
36
+ const o = 1 - t
37
+ const ax = o * fromX + t * x1, ay = o * fromY + t * y1
38
+ const mbx = o * x1 + t * x2, mby = o * y1 + t * y2
39
+ const mcx = o * x2 + t * toX, mcy = o * y2 + t * toY
40
+
41
+ const bx = o * ax + t * mbx, by = o * ay + t * mby
42
+ const mbcx = o * mbx + t * mcx, mbcy = o * mby + t * mcy
43
+
44
+ const cx = o * bx + t * mbcx, cy = o * by + t * mbcy
45
+ data.push(PathCommandMap.C, ax, ay, bx, by, cx, cy)
46
+ }
47
+
48
+ }
49
+
50
+ const { getDerivative } = HighBezierHelper
@@ -0,0 +1,212 @@
1
+ import { IMatrixData, IPathCommandData, IMotionPathData, IRotationPointData, IPointData, IUnitData } from '@leafer-ui/interface'
2
+ import { BezierHelper, MatrixHelper, PathCommandMap, PointHelper, UnitConvert } from '@leafer-ui/draw'
3
+
4
+ import { HighBezierHelper } from './HighBezierHelper'
5
+
6
+
7
+ const { M, L, C, Z } = PathCommandMap
8
+ const tempPoint = {} as IPointData, tempFrom = {} as IPointData
9
+
10
+ export const HighCurveHelper = {
11
+
12
+ transform(data: IPathCommandData, matrix: IMatrixData): void {
13
+ let i: number = 0, command: number
14
+
15
+ const len = data.length
16
+ while (i < len) {
17
+ command = data[i]
18
+ switch (command) {
19
+ case M: //moveto(x, y)
20
+ case L: //lineto(x, y)
21
+ HighCurveHelper.transformPoints(data, matrix, i, 1)
22
+ i += 3
23
+ break
24
+ case C: //bezierCurveTo(x1, y1, x2, y2, x,y)
25
+ HighCurveHelper.transformPoints(data, matrix, i, 3)
26
+ i += 7
27
+ break
28
+ case Z: //closepath()
29
+ i += 1
30
+ }
31
+ }
32
+ },
33
+
34
+ transformPoints(data: IPathCommandData, matrix: IMatrixData, start: number, pointCount: number): void {
35
+ for (let i = start + 1, end = i + pointCount * 2; i < end; i += 2) {
36
+ tempPoint.x = data[i]
37
+ tempPoint.y = data[i + 1]
38
+ MatrixHelper.toOuterPoint(matrix, tempPoint)
39
+ data[i] = tempPoint.x
40
+ data[i + 1] = tempPoint.y
41
+ }
42
+ },
43
+
44
+ getMotionPathData(data: IPathCommandData): IMotionPathData {
45
+ let total = 0, distance: number, segments: number[] = []
46
+ let i = 0, x = 0, y = 0, toX: number, toY: number, command: number
47
+
48
+ const len = data.length
49
+ while (i < len) {
50
+ command = data[i]
51
+ switch (command) {
52
+ case M: //moveto(x, y)
53
+ case L: //lineto(x, y)
54
+ toX = data[i + 1]
55
+ toY = data[i + 2]
56
+ distance = (command === L && i > 0) ? PointHelper.getDistanceFrom(x, y, toX, toY) : 0
57
+ x = toX
58
+ y = toY
59
+ i += 3
60
+ break
61
+ case C: //bezierCurveTo(x1, y1, x2, y2, x,y)
62
+ toX = data[i + 5]
63
+ toY = data[i + 6]
64
+ distance = HighBezierHelper.getDistance(x, y, data[i + 1], data[i + 2], data[i + 3], data[i + 4], toX, toY)
65
+ x = toX
66
+ y = toY
67
+ i += 7
68
+ break
69
+ case Z: //closepath()
70
+ i += 1
71
+ default:
72
+ distance = 0
73
+
74
+ }
75
+
76
+ segments.push(distance)
77
+ total += distance
78
+ }
79
+
80
+ return { total, segments, data }
81
+
82
+ },
83
+
84
+
85
+ getDistancePoint(distanceData: IMotionPathData, motionDistance: number | IUnitData): IRotationPointData {
86
+ const { segments, data } = distanceData
87
+ motionDistance = UnitConvert.number(motionDistance, distanceData.total)
88
+
89
+ let total = 0, distance: number, to = {} as IRotationPointData
90
+ let i = 0, index = 0, x: number = 0, y: number = 0, toX: number, toY: number, command: number
91
+
92
+ const len = data.length
93
+ while (i < len) {
94
+ command = data[i]
95
+ switch (command) {
96
+ case M: //moveto(x, y)
97
+ case L: //lineto(x, y)
98
+ toX = data[i + 1]
99
+ toY = data[i + 2]
100
+ distance = segments[index]
101
+
102
+ if (total + distance > motionDistance || !distanceData.total) {
103
+ if (!i) x = toX, y = toY // first M
104
+ tempFrom.x = x
105
+ tempFrom.y = y
106
+ to.x = toX
107
+ to.y = toY
108
+ PointHelper.getDistancePoint(tempFrom, to, motionDistance - total, true)
109
+ to.rotation = PointHelper.getAngle(tempFrom, to)
110
+ return to
111
+ }
112
+
113
+ x = toX
114
+ y = toY
115
+ i += 3
116
+ break
117
+ case C: //bezierCurveTo(x1, y1, x2, y2, x,y)
118
+ toX = data[i + 5]
119
+ toY = data[i + 6]
120
+ distance = segments[index]
121
+
122
+ if (total + distance > motionDistance) {
123
+ const x1 = data[i + 1], y1 = data[i + 2], x2 = data[i + 3], y2 = data[i + 4]
124
+ motionDistance -= total
125
+ BezierHelper.getPointAndSet(motionDistance / distance, x, y, x1, y1, x2, y2, toX, toY, to)
126
+ BezierHelper.getPointAndSet(Math.max(0, motionDistance - 0.1) / distance, x, y, x1, y1, x2, y2, toX, toY, tempFrom)
127
+ to.rotation = PointHelper.getAngle(tempFrom, to)
128
+ return to
129
+ }
130
+
131
+ x = toX
132
+ y = toY
133
+ i += 7
134
+ break
135
+ case Z: //closepath()
136
+ i += 1
137
+ default:
138
+ distance = 0
139
+ }
140
+
141
+ index++
142
+ total += distance
143
+ }
144
+
145
+ return to
146
+ },
147
+
148
+ getDistancePath(distanceData: IMotionPathData, motionDistance: number | IUnitData): IPathCommandData {
149
+ const { segments, data } = distanceData, path: IPathCommandData = []
150
+ motionDistance = UnitConvert.number(motionDistance, distanceData.total)
151
+
152
+ let total = 0, distance: number, to = {} as IRotationPointData
153
+ let i = 0, index = 0, x: number = 0, y: number = 0, toX: number, toY: number, command: number
154
+
155
+ const len = data.length
156
+ while (i < len) {
157
+ command = data[i]
158
+ switch (command) {
159
+ case M: //moveto(x, y)
160
+ case L: //lineto(x, y)
161
+ toX = data[i + 1]
162
+ toY = data[i + 2]
163
+ distance = segments[index]
164
+
165
+ if (total + distance > motionDistance || !distanceData.total) {
166
+ if (!i) x = toX, y = toY // first M
167
+ tempFrom.x = x
168
+ tempFrom.y = y
169
+ to.x = toX
170
+ to.y = toY
171
+ PointHelper.getDistancePoint(tempFrom, to, motionDistance - total, true)
172
+ path.push(command, to.x, to.y)
173
+ return path
174
+ }
175
+
176
+ x = toX
177
+ y = toY
178
+ i += 3
179
+ path.push(command, x, y)
180
+ break
181
+ case C: //bezierCurveTo(x1, y1, x2, y2, x,y)
182
+ const x1 = data[i + 1], y1 = data[i + 2], x2 = data[i + 3], y2 = data[i + 4]
183
+ toX = data[i + 5]
184
+ toY = data[i + 6]
185
+ distance = segments[index]
186
+
187
+ if (total + distance > motionDistance) {
188
+ HighBezierHelper.cut(path, (motionDistance - total) / distance, x, y, x1, y1, x2, y2, toX, toY)
189
+ return path
190
+ }
191
+
192
+ x = toX
193
+ y = toY
194
+ i += 7
195
+ path.push(command, x1, y1, x2, y2, toX, toY)
196
+ break
197
+ case Z: //closepath()
198
+ i += 1
199
+ path.push(command)
200
+ default:
201
+ distance = 0
202
+
203
+ }
204
+
205
+ index++
206
+ total += distance
207
+ }
208
+
209
+ return path
210
+ }
211
+
212
+ }
@@ -0,0 +1,12 @@
1
+ import { IValue } from '@leafer-ui/interface'
2
+ import { decorateLeafAttr, attr, isNull } from '@leafer-ui/draw'
3
+
4
+ export function motionPathType(defaultValue?: IValue) {
5
+ return decorateLeafAttr(defaultValue, (key: string) => attr({
6
+ set(value: any) {
7
+ this.__setAttr(key, value)
8
+ this.__hasMotionPath = this.motionPath || !isNull(this.motion)
9
+ this.__layout.matrixChanged || this.__layout.matrixChange()
10
+ }
11
+ }))
12
+ }