@leafer-in/viewport 1.1.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.
@@ -0,0 +1,346 @@
1
+ import { MoveEvent, ZoomEvent, PointHelper, DataHelper, Debug, Platform, MathHelper, RotateEvent, Leafer, Bounds, InteractionBase, Dragger, BoundsHelper } from '@leafer-ui/core';
2
+
3
+ function addViewport(leafer, mergeConfig, custom) {
4
+ addViewportConfig(leafer.parentApp ? leafer.parentApp : leafer, mergeConfig);
5
+ if (leafer.isApp || custom)
6
+ return;
7
+ leafer.__eventIds.push(leafer.on_(MoveEvent.BEFORE_MOVE, (e) => {
8
+ leafer.zoomLayer.move(leafer.getValidMove(e.moveX, e.moveY));
9
+ }), leafer.on_(ZoomEvent.BEFORE_ZOOM, (e) => {
10
+ const { zoomLayer } = leafer;
11
+ const changeScale = leafer.getValidScale(e.scale);
12
+ if (changeScale !== 1) {
13
+ PointHelper.scaleOf(zoomLayer, e, changeScale);
14
+ zoomLayer.scale = zoomLayer.__.scaleX * changeScale;
15
+ }
16
+ }));
17
+ }
18
+ function addViewportConfig(leafer, mergeConfig) {
19
+ if (mergeConfig)
20
+ DataHelper.assign(leafer.config, mergeConfig);
21
+ DataHelper.assign(leafer.config, {
22
+ wheel: { preventDefault: true },
23
+ touch: { preventDefault: true },
24
+ pointer: { preventDefaultMenu: true }
25
+ }, leafer.userConfig);
26
+ }
27
+
28
+ function custom(leafer) {
29
+ addViewport(leafer, null, true);
30
+ }
31
+
32
+ function design(leafer) {
33
+ addViewport(leafer, {
34
+ zoom: {
35
+ min: 0.01,
36
+ max: 256
37
+ },
38
+ move: {
39
+ holdSpaceKey: true,
40
+ holdMiddleKey: true,
41
+ }
42
+ });
43
+ }
44
+
45
+ function document(leafer) {
46
+ addViewport(leafer, {
47
+ zoom: { min: 1 },
48
+ move: { scroll: 'limit' }
49
+ });
50
+ }
51
+
52
+ const debug = Debug.get('LeaferTypeCreator');
53
+ const LeaferTypeCreator = {
54
+ list: {},
55
+ register(name, fn) {
56
+ list[name] && debug.repeat(name);
57
+ list[name] = fn;
58
+ },
59
+ run(name, leafer) {
60
+ const fn = list[name];
61
+ fn && fn(leafer);
62
+ }
63
+ };
64
+ const { list, register } = LeaferTypeCreator;
65
+ register('viewport', addViewport);
66
+ register('custom', custom);
67
+ register('design', design);
68
+ register('document', document);
69
+
70
+ const MultiTouchHelper = {
71
+ getData(list) {
72
+ const a = list[0], b = list[1];
73
+ const lastCenter = PointHelper.getCenter(a.from, b.from);
74
+ const center = PointHelper.getCenter(a.to, b.to);
75
+ const move = { x: center.x - lastCenter.x, y: center.y - lastCenter.y };
76
+ const lastDistance = PointHelper.getDistance(a.from, b.from);
77
+ const distance = PointHelper.getDistance(a.to, b.to);
78
+ const scale = distance / lastDistance;
79
+ const rotation = PointHelper.getRotation(a.from, b.from, a.to, b.to);
80
+ return { move, scale, rotation, center };
81
+ }
82
+ };
83
+
84
+ const WheelEventHelper = {
85
+ getMove(event, config) {
86
+ let { moveSpeed } = config;
87
+ let { deltaX, deltaY } = event;
88
+ if (event.shiftKey && !deltaX) {
89
+ deltaX = deltaY;
90
+ deltaY = 0;
91
+ }
92
+ if (deltaX > 50)
93
+ deltaX = Math.max(50, deltaX / 3);
94
+ if (deltaY > 50)
95
+ deltaY = Math.max(50, deltaY / 3);
96
+ return { x: -deltaX * moveSpeed * 2, y: -deltaY * moveSpeed * 2 };
97
+ },
98
+ getScale(event, config) {
99
+ let zoom;
100
+ let scale = 1;
101
+ let { zoomMode, zoomSpeed } = config;
102
+ const delta = event.deltaY || event.deltaX;
103
+ if (zoomMode) {
104
+ zoom = (zoomMode === 'mouse') ? true : (!event.deltaX && (Platform.intWheelDeltaY ? Math.abs(delta) > 17 : Math.ceil(delta) !== delta));
105
+ if (event.shiftKey || event.metaKey || event.ctrlKey)
106
+ zoom = true;
107
+ }
108
+ else {
109
+ zoom = !event.shiftKey && (event.metaKey || event.ctrlKey);
110
+ }
111
+ if (zoom) {
112
+ zoomSpeed = MathHelper.within(zoomSpeed, 0, 1);
113
+ const min = event.deltaY ? config.delta.y : config.delta.x;
114
+ scale = 1 - delta / (min * 4) * zoomSpeed;
115
+ if (scale < 0.5)
116
+ scale = 0.5;
117
+ if (scale >= 1.5)
118
+ scale = 1.5;
119
+ }
120
+ return scale;
121
+ }
122
+ };
123
+
124
+ class Transformer {
125
+ get transforming() { return !!(this.moveData || this.zoomData || this.rotateData); }
126
+ constructor(interaction) {
127
+ this.interaction = interaction;
128
+ }
129
+ move(data) {
130
+ const { interaction } = this;
131
+ if (!data.moveType)
132
+ data.moveType = 'move';
133
+ if (!this.moveData) {
134
+ this.setPath(data);
135
+ this.moveData = Object.assign(Object.assign({}, data), { moveX: 0, moveY: 0 });
136
+ interaction.emit(MoveEvent.START, this.moveData);
137
+ }
138
+ data.path = this.moveData.path;
139
+ interaction.emit(MoveEvent.BEFORE_MOVE, data);
140
+ interaction.emit(MoveEvent.MOVE, data);
141
+ this.transformEndWait();
142
+ }
143
+ zoom(data) {
144
+ const { interaction } = this;
145
+ if (!this.zoomData) {
146
+ this.setPath(data);
147
+ this.zoomData = Object.assign(Object.assign({}, data), { scale: 1 });
148
+ interaction.emit(ZoomEvent.START, this.zoomData);
149
+ }
150
+ data.path = this.zoomData.path;
151
+ interaction.emit(ZoomEvent.BEFORE_ZOOM, data);
152
+ interaction.emit(ZoomEvent.ZOOM, data);
153
+ this.transformEndWait();
154
+ }
155
+ rotate(data) {
156
+ const { interaction } = this;
157
+ if (!this.rotateData) {
158
+ this.setPath(data);
159
+ this.rotateData = Object.assign(Object.assign({}, data), { rotation: 0 });
160
+ interaction.emit(RotateEvent.START, this.rotateData);
161
+ }
162
+ data.path = this.rotateData.path;
163
+ interaction.emit(RotateEvent.BEFORE_ROTATE, data);
164
+ interaction.emit(RotateEvent.ROTATE, data);
165
+ this.transformEndWait();
166
+ }
167
+ setPath(data) {
168
+ const { interaction } = this;
169
+ const { path } = interaction.selector.getByPoint(data, interaction.hitRadius);
170
+ data.path = path;
171
+ interaction.cancelHover();
172
+ }
173
+ transformEndWait() {
174
+ clearTimeout(this.transformTimer);
175
+ this.transformTimer = setTimeout(() => {
176
+ this.transformEnd();
177
+ }, this.interaction.p.transformTime);
178
+ }
179
+ transformEnd() {
180
+ const { interaction, moveData, zoomData, rotateData } = this;
181
+ if (moveData)
182
+ interaction.emit(MoveEvent.END, moveData);
183
+ if (zoomData)
184
+ interaction.emit(ZoomEvent.END, zoomData);
185
+ if (rotateData)
186
+ interaction.emit(RotateEvent.END, rotateData);
187
+ this.reset();
188
+ }
189
+ reset() {
190
+ this.zoomData = this.moveData = this.rotateData = null;
191
+ }
192
+ destroy() {
193
+ this.reset();
194
+ }
195
+ }
196
+
197
+ const leafer = Leafer.prototype;
198
+ const bounds = new Bounds();
199
+ leafer.initType = function (type) {
200
+ LeaferTypeCreator.run(type, this);
201
+ };
202
+ leafer.getValidMove = function (moveX, moveY) {
203
+ const { scroll, disabled } = this.app.config.move;
204
+ if (scroll) {
205
+ const type = scroll === true ? '' : scroll;
206
+ if (type.includes('x'))
207
+ moveX = moveX || moveY, moveY = 0;
208
+ else if (type.includes('y'))
209
+ moveY = moveY || moveX, moveX = 0;
210
+ else
211
+ Math.abs(moveX) > Math.abs(moveY) ? moveY = 0 : moveX = 0;
212
+ if (type.includes('limit')) {
213
+ const { x, y, width, height } = bounds.set(this.__world).addPoint(this.zoomLayer);
214
+ const right = x + width - this.width, bottom = y + height - this.height;
215
+ if (x >= 0 && right <= 0)
216
+ moveX = 0;
217
+ else if (moveX > 0) {
218
+ if (x + moveX > 0)
219
+ moveX = -x;
220
+ }
221
+ else if (moveX < 0 && right + moveX < 0)
222
+ moveX = -right;
223
+ if (y >= 0 && bottom <= 0)
224
+ moveY = 0;
225
+ else if (moveY > 0) {
226
+ if (y + moveY > 0)
227
+ moveY = -y;
228
+ }
229
+ else if (moveY < 0 && bottom + moveY < 0)
230
+ moveY = -bottom;
231
+ }
232
+ }
233
+ return { x: disabled ? 0 : moveX, y: disabled ? 0 : moveY };
234
+ };
235
+ leafer.getValidScale = function (changeScale) {
236
+ const { scaleX } = this.zoomLayer.__, { min, max, disabled } = this.app.config.zoom, absScale = Math.abs(scaleX * changeScale);
237
+ if (min && absScale < min)
238
+ changeScale = min / scaleX;
239
+ else if (max && absScale > max)
240
+ changeScale = max / scaleX;
241
+ return disabled ? 1 : MathHelper.float(changeScale);
242
+ };
243
+
244
+ function getMoveEventData(move, event) {
245
+ return Object.assign(Object.assign({}, event), { moveX: move.x, moveY: move.y });
246
+ }
247
+ function getRotateEventData(rotation, event) {
248
+ return Object.assign(Object.assign({}, event), { rotation });
249
+ }
250
+ function getZoomEventData(scale, event) {
251
+ return Object.assign(Object.assign({}, event), { scale });
252
+ }
253
+ const interaction = InteractionBase.prototype;
254
+ interaction.createTransformer = function () {
255
+ this.transformer = new Transformer(this);
256
+ };
257
+ interaction.move = function (data) {
258
+ this.transformer.move(data);
259
+ };
260
+ interaction.zoom = function (data) {
261
+ this.transformer.zoom(data);
262
+ };
263
+ interaction.rotate = function (data) {
264
+ this.transformer.rotate(data);
265
+ };
266
+ interaction.transformEnd = function () {
267
+ this.transformer.transformEnd();
268
+ };
269
+ interaction.wheel = function (data) {
270
+ const { wheel } = this.config;
271
+ if (wheel.disabled)
272
+ return;
273
+ const scale = wheel.getScale ? wheel.getScale(data, wheel) : WheelEventHelper.getScale(data, wheel);
274
+ scale !== 1 ? this.zoom(getZoomEventData(scale, data)) : this.move(getMoveEventData(wheel.getMove ? wheel.getMove(data, wheel) : WheelEventHelper.getMove(data, wheel), data));
275
+ };
276
+ interaction.multiTouch = function (data, list) {
277
+ if (this.config.multiTouch.disabled)
278
+ return;
279
+ const { move, rotation, scale, center } = MultiTouchHelper.getData(list);
280
+ Object.assign(data, center);
281
+ this.rotate(getRotateEventData(rotation, data));
282
+ this.zoom(getZoomEventData(scale, data));
283
+ this.move(getMoveEventData(move, data));
284
+ };
285
+
286
+ const dragger = Dragger.prototype;
287
+ const { abs } = Math;
288
+ dragger.checkDragEndAnimate = function (data, speed) {
289
+ const { moveX, moveY } = this.dragData;
290
+ const absMoveX = abs(moveX), absMoveY = abs(moveY), minMove = speed ? 1 : 0.1;
291
+ const dragAnimate = this.interaction.m.dragAnimate && this.canAnimate && this.moving && (absMoveX > minMove || absMoveY > minMove);
292
+ if (dragAnimate) {
293
+ const inertia = data.pointerType === 'touch' ? 3 : 1, maxMove = 70;
294
+ speed = speed ? 0.95 : inertia;
295
+ if (absMoveX * speed > maxMove)
296
+ speed = maxMove / absMoveX;
297
+ else if (absMoveY * speed > maxMove)
298
+ speed = maxMove / absMoveY;
299
+ data = Object.assign({}, data);
300
+ PointHelper.move(data, moveX * speed, moveY * speed);
301
+ this.drag(data);
302
+ this.animate(() => { this.dragEnd(data, 1); });
303
+ }
304
+ return dragAnimate;
305
+ };
306
+ dragger.animate = function (func, off) {
307
+ const animateWait = func || this.animateWait;
308
+ if (animateWait)
309
+ this.interaction.target.nextRender(animateWait, null, off);
310
+ this.animateWait = func;
311
+ };
312
+ dragger.checkDragOut = function (data) {
313
+ const { interaction } = this;
314
+ this.autoMoveCancel();
315
+ if (this.dragging && !interaction.shrinkCanvasBounds.hitPoint(data))
316
+ this.autoMoveOnDragOut(data);
317
+ };
318
+ dragger.autoMoveOnDragOut = function (data) {
319
+ const { interaction, downData, canDragOut } = this;
320
+ const { autoDistance, dragOut } = interaction.m;
321
+ if (!dragOut || !canDragOut || !autoDistance)
322
+ return;
323
+ const bounds = interaction.shrinkCanvasBounds;
324
+ const { x, y } = bounds;
325
+ const right = BoundsHelper.maxX(bounds);
326
+ const bottom = BoundsHelper.maxY(bounds);
327
+ const moveX = data.x < x ? autoDistance : (right < data.x ? -autoDistance : 0);
328
+ const moveY = data.y < y ? autoDistance : (bottom < data.y ? -autoDistance : 0);
329
+ let totalX = 0, totalY = 0;
330
+ this.autoMoveTimer = setInterval(() => {
331
+ totalX += moveX;
332
+ totalY += moveY;
333
+ PointHelper.move(downData, moveX, moveY);
334
+ PointHelper.move(this.dragData, moveX, moveY);
335
+ interaction.move(Object.assign(Object.assign({}, data), { moveX, moveY, totalX, totalY, moveType: 'drag' }));
336
+ interaction.pointerMoveReal(data);
337
+ }, 10);
338
+ };
339
+ dragger.autoMoveCancel = function () {
340
+ if (this.autoMoveTimer) {
341
+ clearInterval(this.autoMoveTimer);
342
+ this.autoMoveTimer = 0;
343
+ }
344
+ };
345
+
346
+ export { LeaferTypeCreator, MultiTouchHelper, Transformer, WheelEventHelper, addViewport, addViewportConfig };
@@ -0,0 +1 @@
1
+ import{MoveEvent as t,ZoomEvent as e,PointHelper as o,DataHelper as a,Debug as i,Platform as n,MathHelper as s,RotateEvent as r,Leafer as c,Bounds as m,InteractionBase as h,Dragger as l,BoundsHelper as u}from"@leafer-ui/core";function f(a,i,n){g(a.parentApp?a.parentApp:a,i),a.isApp||n||a.__eventIds.push(a.on_(t.BEFORE_MOVE,(t=>{a.zoomLayer.move(a.getValidMove(t.moveX,t.moveY))})),a.on_(e.BEFORE_ZOOM,(t=>{const{zoomLayer:e}=a,i=a.getValidScale(t.scale);1!==i&&(o.scaleOf(e,t,i),e.scale=e.__.scaleX*i)})))}function g(t,e){e&&a.assign(t.config,e),a.assign(t.config,{wheel:{preventDefault:!0},touch:{preventDefault:!0},pointer:{preventDefaultMenu:!0}},t.userConfig)}const v=i.get("LeaferTypeCreator"),d={list:{},register(t,e){p[t]&&v.repeat(t),p[t]=e},run(t,e){const o=p[t];o&&o(e)}},{list:p,register:D}=d;D("viewport",f),D("custom",(function(t){f(t,null,!0)})),D("design",(function(t){f(t,{zoom:{min:.01,max:256},move:{holdSpaceKey:!0,holdMiddleKey:!0}})})),D("document",(function(t){f(t,{zoom:{min:1},move:{scroll:"limit"}})}));const O={getData(t){const e=t[0],a=t[1],i=o.getCenter(e.from,a.from),n=o.getCenter(e.to,a.to),s={x:n.x-i.x,y:n.y-i.y},r=o.getDistance(e.from,a.from);return{move:s,scale:o.getDistance(e.to,a.to)/r,rotation:o.getRotation(e.from,a.from,e.to,a.to),center:n}}},y={getMove(t,e){let{moveSpeed:o}=e,{deltaX:a,deltaY:i}=t;return t.shiftKey&&!a&&(a=i,i=0),a>50&&(a=Math.max(50,a/3)),i>50&&(i=Math.max(50,i/3)),{x:-a*o*2,y:-i*o*2}},getScale(t,e){let o,a=1,{zoomMode:i,zoomSpeed:r}=e;const c=t.deltaY||t.deltaX;if(i?(o="mouse"===i||!t.deltaX&&(n.intWheelDeltaY?Math.abs(c)>17:Math.ceil(c)!==c),(t.shiftKey||t.metaKey||t.ctrlKey)&&(o=!0)):o=!t.shiftKey&&(t.metaKey||t.ctrlKey),o){r=s.within(r,0,1);a=1-c/(4*(t.deltaY?e.delta.y:e.delta.x))*r,a<.5&&(a=.5),a>=1.5&&(a=1.5)}return a}};class M{get transforming(){return!!(this.moveData||this.zoomData||this.rotateData)}constructor(t){this.interaction=t}move(e){const{interaction:o}=this;e.moveType||(e.moveType="move"),this.moveData||(this.setPath(e),this.moveData=Object.assign(Object.assign({},e),{moveX:0,moveY:0}),o.emit(t.START,this.moveData)),e.path=this.moveData.path,o.emit(t.BEFORE_MOVE,e),o.emit(t.MOVE,e),this.transformEndWait()}zoom(t){const{interaction:o}=this;this.zoomData||(this.setPath(t),this.zoomData=Object.assign(Object.assign({},t),{scale:1}),o.emit(e.START,this.zoomData)),t.path=this.zoomData.path,o.emit(e.BEFORE_ZOOM,t),o.emit(e.ZOOM,t),this.transformEndWait()}rotate(t){const{interaction:e}=this;this.rotateData||(this.setPath(t),this.rotateData=Object.assign(Object.assign({},t),{rotation:0}),e.emit(r.START,this.rotateData)),t.path=this.rotateData.path,e.emit(r.BEFORE_ROTATE,t),e.emit(r.ROTATE,t),this.transformEndWait()}setPath(t){const{interaction:e}=this,{path:o}=e.selector.getByPoint(t,e.hitRadius);t.path=o,e.cancelHover()}transformEndWait(){clearTimeout(this.transformTimer),this.transformTimer=setTimeout((()=>{this.transformEnd()}),this.interaction.p.transformTime)}transformEnd(){const{interaction:o,moveData:a,zoomData:i,rotateData:n}=this;a&&o.emit(t.END,a),i&&o.emit(e.END,i),n&&o.emit(r.END,n),this.reset()}reset(){this.zoomData=this.moveData=this.rotateData=null}destroy(){this.reset()}}const E=c.prototype,T=new m;function b(t,e){return Object.assign(Object.assign({},e),{moveX:t.x,moveY:t.y})}function z(t,e){return Object.assign(Object.assign({},e),{scale:t})}E.initType=function(t){d.run(t,this)},E.getValidMove=function(t,e){const{scroll:o,disabled:a}=this.app.config.move;if(o){const a=!0===o?"":o;if(a.includes("x")?(t=t||e,e=0):a.includes("y")?(e=e||t,t=0):Math.abs(t)>Math.abs(e)?e=0:t=0,a.includes("limit")){const{x:o,y:a,width:i,height:n}=T.set(this.__world).addPoint(this.zoomLayer),s=o+i-this.width,r=a+n-this.height;o>=0&&s<=0?t=0:t>0?o+t>0&&(t=-o):t<0&&s+t<0&&(t=-s),a>=0&&r<=0?e=0:e>0?a+e>0&&(e=-a):e<0&&r+e<0&&(e=-r)}}return{x:a?0:t,y:a?0:e}},E.getValidScale=function(t){const{scaleX:e}=this.zoomLayer.__,{min:o,max:a,disabled:i}=this.app.config.zoom,n=Math.abs(e*t);return o&&n<o?t=o/e:a&&n>a&&(t=a/e),i?1:s.float(t)};const x=h.prototype;x.createTransformer=function(){this.transformer=new M(this)},x.move=function(t){this.transformer.move(t)},x.zoom=function(t){this.transformer.zoom(t)},x.rotate=function(t){this.transformer.rotate(t)},x.transformEnd=function(){this.transformer.transformEnd()},x.wheel=function(t){const{wheel:e}=this.config;if(e.disabled)return;const o=e.getScale?e.getScale(t,e):y.getScale(t,e);1!==o?this.zoom(z(o,t)):this.move(b(e.getMove?e.getMove(t,e):y.getMove(t,e),t))},x.multiTouch=function(t,e){if(this.config.multiTouch.disabled)return;const{move:o,rotation:a,scale:i,center:n}=O.getData(e);Object.assign(t,n),this.rotate(function(t,e){return Object.assign(Object.assign({},e),{rotation:t})}(a,t)),this.zoom(z(i,t)),this.move(b(o,t))};const j=l.prototype,{abs:_}=Math;j.checkDragEndAnimate=function(t,e){const{moveX:a,moveY:i}=this.dragData,n=_(a),s=_(i),r=e?1:.1,c=this.interaction.m.dragAnimate&&this.canAnimate&&this.moving&&(n>r||s>r);if(c){const r="touch"===t.pointerType?3:1,c=70;n*(e=e?.95:r)>c?e=c/n:s*e>c&&(e=c/s),t=Object.assign({},t),o.move(t,a*e,i*e),this.drag(t),this.animate((()=>{this.dragEnd(t,1)}))}return c},j.animate=function(t,e){const o=t||this.animateWait;o&&this.interaction.target.nextRender(o,null,e),this.animateWait=t},j.checkDragOut=function(t){const{interaction:e}=this;this.autoMoveCancel(),this.dragging&&!e.shrinkCanvasBounds.hitPoint(t)&&this.autoMoveOnDragOut(t)},j.autoMoveOnDragOut=function(t){const{interaction:e,downData:a,canDragOut:i}=this,{autoDistance:n,dragOut:s}=e.m;if(!s||!i||!n)return;const r=e.shrinkCanvasBounds,{x:c,y:m}=r,h=u.maxX(r),l=u.maxY(r),f=t.x<c?n:h<t.x?-n:0,g=t.y<m?n:l<t.y?-n:0;let v=0,d=0;this.autoMoveTimer=setInterval((()=>{v+=f,d+=g,o.move(a,f,g),o.move(this.dragData,f,g),e.move(Object.assign(Object.assign({},t),{moveX:f,moveY:g,totalX:v,totalY:d,moveType:"drag"})),e.pointerMoveReal(t)}),10)},j.autoMoveCancel=function(){this.autoMoveTimer&&(clearInterval(this.autoMoveTimer),this.autoMoveTimer=0)};export{d as LeaferTypeCreator,O as MultiTouchHelper,M as Transformer,y as WheelEventHelper,f as addViewport,g as addViewportConfig};