jsxgraph 1.3.1 → 1.4.2
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/README.md +2 -2
- package/distrib/README.md +2 -2
- package/distrib/geogebra.min.js +3 -3
- package/distrib/geonext.min.js +3 -3
- package/distrib/index.d.ts +4964 -4627
- package/distrib/intergeo.min.js +3 -3
- package/distrib/jsxgraph.css +10 -15
- package/distrib/jsxgraphcore.js +9 -25
- package/distrib/jsxgraphsrc.js +28437 -25331
- package/distrib/sketch.min.js +3 -3
- package/package.json +11 -22
- package/src/base/board.js +555 -427
- package/src/base/chart.js +1 -1
- package/src/base/circle.js +23 -1
- package/src/base/composition.js +1 -1
- package/src/base/constants.js +33 -11
- package/src/base/coords.js +4 -4
- package/src/base/coordselement.js +47 -20
- package/src/base/curve.js +308 -117
- package/src/base/element.js +80 -51
- package/src/base/foreignobject.js +463 -0
- package/src/base/group.js +2 -2
- package/src/base/image.js +12 -15
- package/src/base/line.js +1 -1
- package/src/base/point.js +20 -41
- package/src/base/polygon.js +75 -18
- package/src/base/text.js +116 -63
- package/src/base/ticks.js +35 -12
- package/src/base/transformation.js +1 -1
- package/src/base/turtle.js +1 -1
- package/src/element/arc.js +1 -1
- package/src/element/button.js +29 -2
- package/src/element/checkbox.js +31 -1
- package/src/element/comb.js +5 -2
- package/src/element/composition.js +27 -6
- package/src/element/conic.js +46 -5
- package/src/element/input.js +32 -1
- package/src/element/locus.js +2 -2
- package/src/element/measure.js +9 -4
- package/src/element/sector.js +46 -12
- package/src/element/slider.js +17 -12
- package/src/element/slopetriangle.js +1 -1
- package/src/jsxgraph.js +28 -9
- package/src/jxg.js +4 -3
- package/src/loadjsxgraph.js +3 -2
- package/src/math/bst.js +1 -1
- package/src/math/clip.js +550 -345
- package/src/math/complex.js +1 -1
- package/src/math/extrapolate.js +1 -1
- package/src/math/geometry.js +109 -128
- package/src/math/ia.js +290 -21
- package/src/math/math.js +30 -1
- package/src/math/metapost.js +1 -1
- package/src/math/nlp.js +25 -5
- package/src/math/numerics.js +183 -4
- package/src/math/plot.js +4 -4
- package/src/math/poly.js +1 -1
- package/src/math/probfuncs.js +2 -1
- package/src/math/qdt.js +68 -62
- package/src/math/statistics.js +58 -7
- package/src/math/symbolic.js +1 -1
- package/src/options.js +393 -115
- package/src/parser/ca.js +1297 -1291
- package/src/parser/datasource.js +1 -1
- package/src/parser/geonext.js +6 -6
- package/src/parser/jessiecode.js +378 -79
- package/src/parser/jessiescript.js +1 -1
- package/src/reader/cinderella.js +1 -1
- package/src/reader/file.js +1 -1
- package/src/reader/geogebra.js +1 -1
- package/src/reader/geonext.js +1 -1
- package/src/reader/graph.js +1 -1
- package/src/reader/intergeo.js +1 -1
- package/src/reader/sketch.js +25 -17
- package/src/renderer/abstract.js +25 -7
- package/src/renderer/canvas.js +20 -15
- package/src/renderer/no.js +11 -4
- package/src/renderer/svg.js +68 -49
- package/src/renderer/vml.js +36 -32
- package/src/server/server.js +1 -1
- package/src/utils/base64.js +2 -2
- package/src/utils/color.js +147 -3
- package/src/utils/dump.js +20 -14
- package/src/utils/env.js +26 -62
- package/src/utils/event.js +1 -1
- package/src/utils/expect.js +1 -1
- package/src/utils/type.js +30 -19
- package/src/utils/xml.js +1 -1
- package/src/utils/zip.js +1 -1
- package/CHANGELOG.md +0 -1305
package/src/base/board.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Copyright 2008-
|
|
2
|
+
Copyright 2008-2022
|
|
3
3
|
Matthias Ehmann,
|
|
4
4
|
Michael Gerhaeuser,
|
|
5
5
|
Carsten Miller,
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
define([
|
|
66
66
|
'jxg', 'base/constants', 'base/coords', 'options', 'math/numerics', 'math/math', 'math/geometry', 'math/complex',
|
|
67
67
|
'math/statistics',
|
|
68
|
-
'parser/jessiecode', '
|
|
69
|
-
'base/
|
|
70
|
-
], function (JXG, Const, Coords, Options, Numerics, Mat, Geometry, Complex, Statistics, JessieCode,
|
|
71
|
-
EventEmitter, Env,
|
|
68
|
+
'parser/jessiecode', 'utils/color', 'utils/type', 'utils/event', 'utils/env',
|
|
69
|
+
'base/composition'
|
|
70
|
+
], function (JXG, Const, Coords, Options, Numerics, Mat, Geometry, Complex, Statistics, JessieCode, Color, Type,
|
|
71
|
+
EventEmitter, Env, Composition) {
|
|
72
72
|
|
|
73
73
|
'use strict';
|
|
74
74
|
|
|
@@ -120,20 +120,20 @@ define([
|
|
|
120
120
|
this.BOARD_MODE_MOVE_ORIGIN = 0x0002;
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
|
-
* Update is made with
|
|
123
|
+
* Update is made with high quality, e.g. graphs are evaluated at much more points.
|
|
124
124
|
* @type Number
|
|
125
125
|
* @constant
|
|
126
126
|
* @see JXG.Board#updateQuality
|
|
127
127
|
*/
|
|
128
|
-
this.
|
|
128
|
+
this.BOARD_MODE_ZOOM = 0x0011;
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* Update is made with
|
|
131
|
+
* Update is made with low quality, e.g. graphs are evaluated at a lesser amount of points.
|
|
132
132
|
* @type Number
|
|
133
133
|
* @constant
|
|
134
134
|
* @see JXG.Board#updateQuality
|
|
135
135
|
*/
|
|
136
|
-
this.
|
|
136
|
+
this.BOARD_QUALITY_LOW = 0x1;
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
139
|
* Update is made with high quality, e.g. graphs are evaluated at much more points.
|
|
@@ -141,7 +141,7 @@ define([
|
|
|
141
141
|
* @constant
|
|
142
142
|
* @see JXG.Board#updateQuality
|
|
143
143
|
*/
|
|
144
|
-
this.
|
|
144
|
+
this.BOARD_QUALITY_HIGH = 0x2;
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
147
|
* Pointer to the document element containing the board.
|
|
@@ -174,11 +174,16 @@ define([
|
|
|
174
174
|
/**
|
|
175
175
|
* A reference to this boards renderer.
|
|
176
176
|
* @type JXG.AbstractRenderer
|
|
177
|
+
* @name JXG.Board#renderer
|
|
178
|
+
* @private
|
|
179
|
+
* @ignore
|
|
177
180
|
*/
|
|
178
181
|
this.renderer = renderer;
|
|
179
182
|
|
|
180
183
|
/**
|
|
181
184
|
* Grids keeps track of all grids attached to this board.
|
|
185
|
+
* @type Array
|
|
186
|
+
* @private
|
|
182
187
|
*/
|
|
183
188
|
this.grids = [];
|
|
184
189
|
|
|
@@ -204,6 +209,7 @@ define([
|
|
|
204
209
|
* usrCoords and scrCoords. usrCoords always equals [1, 0, 0] and scrCoords
|
|
205
210
|
* stores the boards origin in homogeneous screen coordinates.
|
|
206
211
|
* @type Object
|
|
212
|
+
* @private
|
|
207
213
|
*/
|
|
208
214
|
this.origin = {};
|
|
209
215
|
this.origin.usrCoords = [1, 0, 0];
|
|
@@ -212,44 +218,56 @@ define([
|
|
|
212
218
|
/**
|
|
213
219
|
* Zoom factor in X direction. It only stores the zoom factor to be able
|
|
214
220
|
* to get back to 100% in zoom100().
|
|
221
|
+
* @name JXG.Board.zoomX
|
|
215
222
|
* @type Number
|
|
223
|
+
* @private
|
|
224
|
+
* @ignore
|
|
216
225
|
*/
|
|
217
226
|
this.zoomX = zoomX;
|
|
218
227
|
|
|
219
228
|
/**
|
|
220
229
|
* Zoom factor in Y direction. It only stores the zoom factor to be able
|
|
221
230
|
* to get back to 100% in zoom100().
|
|
231
|
+
* @name JXG.Board.zoomY
|
|
222
232
|
* @type Number
|
|
233
|
+
* @private
|
|
234
|
+
* @ignore
|
|
223
235
|
*/
|
|
224
236
|
this.zoomY = zoomY;
|
|
225
237
|
|
|
226
238
|
/**
|
|
227
239
|
* The number of pixels which represent one unit in user-coordinates in x direction.
|
|
228
240
|
* @type Number
|
|
241
|
+
* @private
|
|
229
242
|
*/
|
|
230
243
|
this.unitX = unitX * this.zoomX;
|
|
231
244
|
|
|
232
245
|
/**
|
|
233
246
|
* The number of pixels which represent one unit in user-coordinates in y direction.
|
|
234
247
|
* @type Number
|
|
248
|
+
* @private
|
|
235
249
|
*/
|
|
236
250
|
this.unitY = unitY * this.zoomY;
|
|
237
251
|
|
|
238
252
|
/**
|
|
239
253
|
* Keep aspect ratio if bounding box is set and the width/height ratio differs from the
|
|
240
254
|
* width/height ratio of the canvas.
|
|
255
|
+
* @type Boolean
|
|
256
|
+
* @private
|
|
241
257
|
*/
|
|
242
258
|
this.keepaspectratio = false;
|
|
243
259
|
|
|
244
260
|
/**
|
|
245
261
|
* Canvas width.
|
|
246
262
|
* @type Number
|
|
263
|
+
* @private
|
|
247
264
|
*/
|
|
248
265
|
this.canvasWidth = canvasWidth;
|
|
249
266
|
|
|
250
267
|
/**
|
|
251
268
|
* Canvas Height
|
|
252
269
|
* @type Number
|
|
270
|
+
* @private
|
|
253
271
|
*/
|
|
254
272
|
this.canvasHeight = canvasHeight;
|
|
255
273
|
|
|
@@ -379,15 +397,15 @@ define([
|
|
|
379
397
|
|
|
380
398
|
/**
|
|
381
399
|
* References to the object that is dragged with the mouse on the board.
|
|
382
|
-
* @type
|
|
383
|
-
* @see
|
|
400
|
+
* @type JXG.GeometryElement
|
|
401
|
+
* @see JXG.Board#touches
|
|
384
402
|
*/
|
|
385
403
|
this.mouse = {};
|
|
386
404
|
|
|
387
405
|
/**
|
|
388
406
|
* Keeps track on touched elements, like {@link JXG.Board#mouse} does for mouse events.
|
|
389
407
|
* @type Array
|
|
390
|
-
* @see
|
|
408
|
+
* @see JXG.Board#mouse
|
|
391
409
|
*/
|
|
392
410
|
this.touches = [];
|
|
393
411
|
|
|
@@ -412,6 +430,13 @@ define([
|
|
|
412
430
|
*/
|
|
413
431
|
this.touchMoveLast = 0;
|
|
414
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Contains the pointerId of the last touchMove event which was not thrown away or since
|
|
435
|
+
* touchStart because Android's Webkit browser fires too much of them.
|
|
436
|
+
* @type Number
|
|
437
|
+
*/
|
|
438
|
+
this.touchMoveLastId = Infinity;
|
|
439
|
+
|
|
415
440
|
/**
|
|
416
441
|
* Contains the last time (epoch, msec) since the last getCoordsTopLeftCorner call which was not thrown away.
|
|
417
442
|
* @type Number
|
|
@@ -482,7 +507,7 @@ define([
|
|
|
482
507
|
|
|
483
508
|
/**
|
|
484
509
|
* A flag which stores if the board registered pointer events.
|
|
485
|
-
* @type
|
|
510
|
+
* @type Boolean
|
|
486
511
|
* @default false
|
|
487
512
|
*/
|
|
488
513
|
this.hasPointerHandlers = false;
|
|
@@ -503,14 +528,14 @@ define([
|
|
|
503
528
|
|
|
504
529
|
/**
|
|
505
530
|
* A flag which tells us if the board has a pointerUp event registered at the moment.
|
|
506
|
-
* @type
|
|
531
|
+
* @type Boolean
|
|
507
532
|
* @default false
|
|
508
533
|
*/
|
|
509
534
|
this.hasPointerUp = false;
|
|
510
535
|
|
|
511
536
|
/**
|
|
512
537
|
* Offset for large coords elements like images
|
|
513
|
-
* @type
|
|
538
|
+
* @type Array
|
|
514
539
|
* @private
|
|
515
540
|
* @default [0, 0]
|
|
516
541
|
*/
|
|
@@ -518,31 +543,36 @@ define([
|
|
|
518
543
|
|
|
519
544
|
/**
|
|
520
545
|
* Stores the input device used in the last down or move event.
|
|
521
|
-
* @type
|
|
546
|
+
* @type String
|
|
522
547
|
* @private
|
|
523
548
|
* @default 'mouse'
|
|
524
549
|
*/
|
|
525
550
|
this._inputDevice = 'mouse';
|
|
526
551
|
|
|
552
|
+
/**
|
|
553
|
+
* Keeps a list of pointer devices which are currently touching the screen.
|
|
554
|
+
* @type Array
|
|
555
|
+
* @private
|
|
556
|
+
*/
|
|
527
557
|
this._board_touches = [];
|
|
528
558
|
|
|
529
559
|
/**
|
|
530
560
|
* A flag which tells us if the board is in the selecting mode
|
|
531
|
-
* @type
|
|
561
|
+
* @type Boolean
|
|
532
562
|
* @default false
|
|
533
563
|
*/
|
|
534
564
|
this.selectingMode = false;
|
|
535
565
|
|
|
536
566
|
/**
|
|
537
567
|
* A flag which tells us if the user is selecting
|
|
538
|
-
* @type
|
|
568
|
+
* @type Boolean
|
|
539
569
|
* @default false
|
|
540
570
|
*/
|
|
541
571
|
this.isSelecting = false;
|
|
542
572
|
|
|
543
573
|
/**
|
|
544
574
|
* A flag which tells us if the user is scrolling the viewport
|
|
545
|
-
* @type
|
|
575
|
+
* @type Boolean
|
|
546
576
|
* @private
|
|
547
577
|
* @default false
|
|
548
578
|
* @see JXG.Board#scrollListener
|
|
@@ -551,7 +581,7 @@ define([
|
|
|
551
581
|
|
|
552
582
|
/**
|
|
553
583
|
* A flag which tells us if a resize is in process
|
|
554
|
-
* @type
|
|
584
|
+
* @type Boolean
|
|
555
585
|
* @private
|
|
556
586
|
* @default false
|
|
557
587
|
* @see JXG.Board#resizeListener
|
|
@@ -560,7 +590,7 @@ define([
|
|
|
560
590
|
|
|
561
591
|
/**
|
|
562
592
|
* A bounding box for the selection
|
|
563
|
-
* @type
|
|
593
|
+
* @type Array
|
|
564
594
|
* @default [ [0,0], [0,0] ]
|
|
565
595
|
*/
|
|
566
596
|
this.selectingBox = [[0, 0], [0, 0]];
|
|
@@ -764,17 +794,20 @@ define([
|
|
|
764
794
|
* @see JXG.Board#mouseMoveListener
|
|
765
795
|
*/
|
|
766
796
|
checkFrameRate: function(evt) {
|
|
767
|
-
var
|
|
768
|
-
|
|
769
|
-
if ((time - this.touchMoveLast) * this.attr.maxframerate < 1000) {
|
|
770
|
-
// this.updateQuality = this.BOARD_QUALITY_HIGH;
|
|
771
|
-
// this.triggerEventHandlers(['touchmove', 'move'], [evt, this.mode]);
|
|
797
|
+
var handleEvt = false,
|
|
798
|
+
time = new Date().getTime();
|
|
772
799
|
|
|
773
|
-
|
|
800
|
+
if (Type.exists(evt.pointerId) && this.touchMoveLastId !== evt.pointerId) {
|
|
801
|
+
handleEvt = true;
|
|
802
|
+
this.touchMoveLastId = evt.pointerId;
|
|
774
803
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
804
|
+
if (!handleEvt && (time - this.touchMoveLast) * this.attr.maxframerate >= 1000) {
|
|
805
|
+
handleEvt = true;
|
|
806
|
+
}
|
|
807
|
+
if (handleEvt) {
|
|
808
|
+
this.touchMoveLast = time;
|
|
809
|
+
}
|
|
810
|
+
return handleEvt;
|
|
778
811
|
},
|
|
779
812
|
|
|
780
813
|
/**
|
|
@@ -903,7 +936,7 @@ define([
|
|
|
903
936
|
absPos,
|
|
904
937
|
v;
|
|
905
938
|
|
|
906
|
-
//
|
|
939
|
+
// Position of cursor using clientX/Y
|
|
907
940
|
absPos = Env.getPosition(e, i, this.document);
|
|
908
941
|
|
|
909
942
|
/**
|
|
@@ -912,6 +945,7 @@ define([
|
|
|
912
945
|
if (!Type.exists(this.cssTransMat)) {
|
|
913
946
|
this.updateCSSTransforms();
|
|
914
947
|
}
|
|
948
|
+
// Position relative to the top left corner
|
|
915
949
|
v = [1, absPos[0] - cPos[0], absPos[1] - cPos[1]];
|
|
916
950
|
v = Mat.matVecMult(this.cssTransMat, v);
|
|
917
951
|
v[1] /= v[0];
|
|
@@ -1129,8 +1163,8 @@ define([
|
|
|
1129
1163
|
* @param {Object} o The touch object that is dragged: {JXG.Board#touches}.
|
|
1130
1164
|
* @param {Object} evt The event object that lead to this movement.
|
|
1131
1165
|
*/
|
|
1132
|
-
twoFingerMove: function (
|
|
1133
|
-
var
|
|
1166
|
+
twoFingerMove: function (o, id, evt) {
|
|
1167
|
+
var drag;
|
|
1134
1168
|
|
|
1135
1169
|
if (Type.exists(o) && Type.exists(o.obj)) {
|
|
1136
1170
|
drag = o.obj;
|
|
@@ -1138,60 +1172,51 @@ define([
|
|
|
1138
1172
|
return;
|
|
1139
1173
|
}
|
|
1140
1174
|
|
|
1141
|
-
// New finger position
|
|
1142
|
-
np1c = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(p1[0], p1[1]), this);
|
|
1143
|
-
np2c = new Coords(Const.COORDS_BY_SCREEN, this.getScrCoordsOfMouse(p2[0], p2[1]), this);
|
|
1144
|
-
|
|
1145
1175
|
if (drag.elementClass === Const.OBJECT_CLASS_LINE ||
|
|
1146
|
-
|
|
1147
|
-
this.twoFingerTouchObject(
|
|
1176
|
+
drag.type === Const.OBJECT_TYPE_POLYGON) {
|
|
1177
|
+
this.twoFingerTouchObject(o.targets, drag, id);
|
|
1148
1178
|
} else if (drag.elementClass === Const.OBJECT_CLASS_CIRCLE) {
|
|
1149
|
-
this.twoFingerTouchCircle(
|
|
1179
|
+
this.twoFingerTouchCircle(o.targets, drag, id);
|
|
1150
1180
|
}
|
|
1151
1181
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
o.targets[0].Yprev = np1c.scrCoords[2];
|
|
1156
|
-
o.targets[1].Xprev = np2c.scrCoords[1];
|
|
1157
|
-
o.targets[1].Yprev = np2c.scrCoords[2];
|
|
1182
|
+
if (evt) {
|
|
1183
|
+
drag.triggerEventHandlers(['touchdrag', 'drag'], [evt]);
|
|
1184
|
+
}
|
|
1158
1185
|
},
|
|
1159
1186
|
|
|
1160
1187
|
/**
|
|
1161
1188
|
* Moves, rotates and scales a line or polygon with two fingers.
|
|
1162
|
-
* @param {
|
|
1163
|
-
* @param {JXG.Coords} np2c x,y coordinates of second touch
|
|
1164
|
-
* @param {object} o The touch object that is dragged: {JXG.Board#touches}.
|
|
1189
|
+
* @param {Array} tar Array conatining touch event objects: {JXG.Board#touches.targets}.
|
|
1165
1190
|
* @param {object} drag The object that is dragged:
|
|
1166
|
-
* @param {
|
|
1191
|
+
* @param {Number} id pointerId of the event. In case of old touch event this is emulated.
|
|
1167
1192
|
*/
|
|
1168
|
-
twoFingerTouchObject: function (
|
|
1169
|
-
var
|
|
1170
|
-
nmid, omid, nd, od,
|
|
1193
|
+
twoFingerTouchObject: function (tar, drag, id) {
|
|
1194
|
+
var np, op, nd, od,
|
|
1171
1195
|
d, alpha,
|
|
1172
|
-
S, t1,
|
|
1196
|
+
S, t1, t3, t4, t5,
|
|
1173
1197
|
ar, i, len,
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
if (Type.exists(o.targets[0]) &&
|
|
1177
|
-
Type.exists(o.targets[1]) &&
|
|
1178
|
-
!isNaN(o.targets[0].Xprev + o.targets[0].Yprev + o.targets[1].Xprev + o.targets[1].Yprev)) {
|
|
1198
|
+
fixEl, moveEl, fix;
|
|
1179
1199
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
np2 = np2c.usrCoords;
|
|
1200
|
+
if (Type.exists(tar[0]) && Type.exists(tar[1]) &&
|
|
1201
|
+
!isNaN(tar[0].Xprev + tar[0].Yprev + tar[1].Xprev + tar[1].Yprev)) {
|
|
1183
1202
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1203
|
+
if (id === tar[0].num) {
|
|
1204
|
+
fixEl = tar[1];
|
|
1205
|
+
moveEl = tar[0];
|
|
1206
|
+
} else {
|
|
1207
|
+
fixEl = tar[0];
|
|
1208
|
+
moveEl = tar[1];
|
|
1209
|
+
}
|
|
1187
1210
|
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1211
|
+
fix = (new Coords(Const.COORDS_BY_SCREEN, [fixEl.Xprev, fixEl.Yprev], this)).usrCoords;
|
|
1212
|
+
// Previous finger position
|
|
1213
|
+
op = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.Xprev, moveEl.Yprev], this)).usrCoords;
|
|
1214
|
+
// New finger position
|
|
1215
|
+
np = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.X, moveEl.Y], this)).usrCoords;
|
|
1191
1216
|
|
|
1192
1217
|
// Old and new directions
|
|
1193
|
-
od = Mat.crossProduct(
|
|
1194
|
-
nd = Mat.crossProduct(
|
|
1218
|
+
od = Mat.crossProduct(fix, op);
|
|
1219
|
+
nd = Mat.crossProduct(fix, np);
|
|
1195
1220
|
|
|
1196
1221
|
// Intersection between the two directions
|
|
1197
1222
|
S = Mat.crossProduct(od, nd);
|
|
@@ -1201,45 +1226,18 @@ define([
|
|
|
1201
1226
|
return;
|
|
1202
1227
|
}
|
|
1203
1228
|
|
|
1204
|
-
|
|
1205
|
-
S[1] /= S[0];
|
|
1206
|
-
S[2] /= S[0];
|
|
1229
|
+
alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));
|
|
1207
1230
|
|
|
1208
|
-
|
|
1209
|
-
// iOS touch events contain the angle for free
|
|
1210
|
-
alpha = evt.rotation - this.previousRotation;
|
|
1211
|
-
this.previousRotation = evt.rotation;
|
|
1212
|
-
alpha *= -pi180;
|
|
1213
|
-
} else {
|
|
1214
|
-
// For pointer events, the rotation angle has to be calculated.
|
|
1215
|
-
alpha = Geometry.rad(omid.slice(1), S.slice(1), nmid.slice(1));
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
t1 = this.create('transform', [alpha, S[1], S[2]], {type: 'rotate'});
|
|
1219
|
-
|
|
1220
|
-
// Old midpoint of fingers after first transformation:
|
|
1231
|
+
t1 = this.create('transform', [alpha, [fix[1], fix[2]]], {type: 'rotate'});
|
|
1221
1232
|
t1.update();
|
|
1222
|
-
omid = Mat.matVecMult(t1.matrix, omid);
|
|
1223
|
-
omid[1] /= omid[0];
|
|
1224
|
-
omid[2] /= omid[0];
|
|
1225
1233
|
|
|
1226
|
-
// Shift to the new mid point
|
|
1227
|
-
t2 = this.create('transform', [nmid[1] - omid[1], nmid[2] - omid[2]], {type: 'translate'});
|
|
1228
|
-
t2.update();
|
|
1229
|
-
|
|
1230
|
-
t1.melt(t2);
|
|
1231
1234
|
if (Type.evaluate(drag.visProp.scalable)) {
|
|
1232
1235
|
// Scale
|
|
1233
|
-
|
|
1234
|
-
d = evt.scale / this.previousScale;
|
|
1235
|
-
this.previousScale = evt.scale;
|
|
1236
|
-
} else {
|
|
1237
|
-
d = Geometry.distance(np1, np2) / Geometry.distance(op1, op2);
|
|
1238
|
-
}
|
|
1236
|
+
d = Geometry.distance(np, fix) / Geometry.distance(op, fix);
|
|
1239
1237
|
|
|
1240
|
-
t3 = this.create('transform', [-
|
|
1238
|
+
t3 = this.create('transform', [-fix[1], -fix[2]], {type: 'translate'});
|
|
1241
1239
|
t4 = this.create('transform', [d, d], {type: 'scale'});
|
|
1242
|
-
t5 = this.create('transform', [
|
|
1240
|
+
t5 = this.create('transform', [fix[1], fix[2]], {type: 'translate'});
|
|
1243
1241
|
t1.melt(t3).melt(t4).melt(t5);
|
|
1244
1242
|
}
|
|
1245
1243
|
|
|
@@ -1270,46 +1268,48 @@ define([
|
|
|
1270
1268
|
|
|
1271
1269
|
/*
|
|
1272
1270
|
* Moves, rotates and scales a circle with two fingers.
|
|
1273
|
-
* @param {
|
|
1274
|
-
* @param {JXG.Coords} np2c x,y coordinates of second touch
|
|
1275
|
-
* @param {object} o The touch object that is dragged: {JXG.Board#touches}.
|
|
1271
|
+
* @param {Array} tar Array conatining touch event objects: {JXG.Board#touches.targets}.
|
|
1276
1272
|
* @param {object} drag The object that is dragged:
|
|
1273
|
+
* @param {Number} id pointerId of the event. In case of old touch event this is emulated.
|
|
1277
1274
|
*/
|
|
1278
|
-
twoFingerTouchCircle: function (
|
|
1279
|
-
var
|
|
1280
|
-
d, alpha, t1, t2, t3, t4
|
|
1275
|
+
twoFingerTouchCircle: function (tar, drag, id) {
|
|
1276
|
+
var fixEl, moveEl, np, op, fix,
|
|
1277
|
+
d, alpha, t1, t2, t3, t4;
|
|
1281
1278
|
|
|
1282
|
-
if (drag.method === 'pointCircle' ||
|
|
1283
|
-
drag.method === 'pointLine') {
|
|
1279
|
+
if (drag.method === 'pointCircle' || drag.method === 'pointLine') {
|
|
1284
1280
|
return;
|
|
1285
1281
|
}
|
|
1286
1282
|
|
|
1287
|
-
if (Type.exists(
|
|
1288
|
-
|
|
1289
|
-
!isNaN(o.targets[0].Xprev + o.targets[0].Yprev + o.targets[1].Xprev + o.targets[1].Yprev)) {
|
|
1283
|
+
if (Type.exists(tar[0]) && Type.exists(tar[1]) &&
|
|
1284
|
+
!isNaN(tar[0].Xprev + tar[0].Yprev + tar[1].Xprev + tar[1].Yprev)) {
|
|
1290
1285
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1286
|
+
if (id === tar[0].num) {
|
|
1287
|
+
fixEl = tar[1];
|
|
1288
|
+
moveEl = tar[0];
|
|
1289
|
+
} else {
|
|
1290
|
+
fixEl = tar[0];
|
|
1291
|
+
moveEl = tar[1];
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
fix = (new Coords(Const.COORDS_BY_SCREEN, [fixEl.Xprev, fixEl.Yprev], this)).usrCoords;
|
|
1293
1295
|
// Previous finger position
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
+
op = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.Xprev, moveEl.Yprev], this)).usrCoords;
|
|
1297
|
+
// New finger position
|
|
1298
|
+
np = (new Coords(Const.COORDS_BY_SCREEN, [moveEl.X, moveEl.Y], this)).usrCoords;
|
|
1296
1299
|
|
|
1297
|
-
|
|
1298
|
-
t1 = this.create('transform', [np1[1] - op1[1], np1[2] - op1[2]], {type: 'translate'});
|
|
1299
|
-
alpha = Geometry.rad(op2.slice(1), np1.slice(1), np2.slice(1));
|
|
1300
|
+
alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));
|
|
1300
1301
|
|
|
1301
1302
|
// Rotate and scale by the movement of the second finger
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
t1.melt(t2)
|
|
1305
|
-
|
|
1303
|
+
t1 = this.create('transform', [-fix[1], -fix[2]], {type: 'translate'});
|
|
1304
|
+
t2 = this.create('transform', [alpha], {type: 'rotate'});
|
|
1305
|
+
t1.melt(t2);
|
|
1306
1306
|
if (Type.evaluate(drag.visProp.scalable)) {
|
|
1307
|
-
d = Geometry.distance(
|
|
1308
|
-
|
|
1309
|
-
t1.melt(
|
|
1307
|
+
d = Geometry.distance(fix, np) / Geometry.distance(fix, op);
|
|
1308
|
+
t3 = this.create('transform', [d, d], {type: 'scale'});
|
|
1309
|
+
t1.melt(t3);
|
|
1310
1310
|
}
|
|
1311
|
-
|
|
1312
|
-
t1.melt(
|
|
1311
|
+
t4 = this.create('transform', [fix[1], fix[2]], {type: 'translate'});
|
|
1312
|
+
t1.melt(t4);
|
|
1313
1313
|
|
|
1314
1314
|
if (drag.center.draggable()) {
|
|
1315
1315
|
t1.applyOnce([drag.center]);
|
|
@@ -1664,7 +1664,7 @@ define([
|
|
|
1664
1664
|
},
|
|
1665
1665
|
|
|
1666
1666
|
addKeyboardEventHandlers: function() {
|
|
1667
|
-
if (!this.hasKeyboardHandlers && Env.isBrowser) {
|
|
1667
|
+
if (this.attr.keyboard.enabled && !this.hasKeyboardHandlers && Env.isBrowser) {
|
|
1668
1668
|
Env.addEvent(this.containerObj, 'keydown', this.keyDownListener, this);
|
|
1669
1669
|
Env.addEvent(this.containerObj, 'focusin', this.keyFocusInListener, this);
|
|
1670
1670
|
Env.addEvent(this.containerObj, 'focusout', this.keyFocusOutListener, this);
|
|
@@ -1982,7 +1982,7 @@ define([
|
|
|
1982
1982
|
|
|
1983
1983
|
/**
|
|
1984
1984
|
*
|
|
1985
|
-
* Check if pointer event is already registered in
|
|
1985
|
+
* Check if pointer event is already registered in {@link JXG.Board#_board_touches}.
|
|
1986
1986
|
*
|
|
1987
1987
|
* @param {Object} evt Event object
|
|
1988
1988
|
* @return {Boolean} true if down event has already been sent.
|
|
@@ -2001,14 +2001,16 @@ define([
|
|
|
2001
2001
|
|
|
2002
2002
|
/**
|
|
2003
2003
|
*
|
|
2004
|
-
*
|
|
2004
|
+
* Store the position of a pointer event.
|
|
2005
|
+
* If not yet done, registers a pointer event in {@link JXG.Board#_board_touches}.
|
|
2005
2006
|
* Allows to follow the path of that finger on the screen.
|
|
2007
|
+
* Only two simultaneous touches are supported.
|
|
2006
2008
|
*
|
|
2007
2009
|
* @param {Object} evt Event object
|
|
2008
2010
|
* @returns {JXG.Board} Reference to the board
|
|
2009
2011
|
* @private
|
|
2010
2012
|
*/
|
|
2011
|
-
|
|
2013
|
+
_pointerStorePosition: function (evt) {
|
|
2012
2014
|
var i, found;
|
|
2013
2015
|
|
|
2014
2016
|
for (i = 0, found = false; i < this._board_touches.length; i++) {
|
|
@@ -2020,7 +2022,8 @@ define([
|
|
|
2020
2022
|
}
|
|
2021
2023
|
}
|
|
2022
2024
|
|
|
2023
|
-
|
|
2025
|
+
// Restrict the number of simultaneous touches to 2
|
|
2026
|
+
if (!found && this._board_touches.length < 2) {
|
|
2024
2027
|
this._board_touches.push({
|
|
2025
2028
|
pointerId: evt.pointerId,
|
|
2026
2029
|
clientX: evt.clientX,
|
|
@@ -2032,14 +2035,14 @@ define([
|
|
|
2032
2035
|
},
|
|
2033
2036
|
|
|
2034
2037
|
/**
|
|
2035
|
-
* Deregisters a pointer event in
|
|
2036
|
-
*
|
|
2038
|
+
* Deregisters a pointer event in {@link JXG.Board#_board_touches}.
|
|
2039
|
+
* It happens if a finger has been lifted from the screen.
|
|
2037
2040
|
*
|
|
2038
|
-
* @param {Object}
|
|
2041
|
+
* @param {Object} evt Event object
|
|
2039
2042
|
* @returns {JXG.Board} Reference to the board
|
|
2040
2043
|
* @private
|
|
2041
2044
|
*/
|
|
2042
|
-
|
|
2045
|
+
_pointerRemoveTouches: function (evt) {
|
|
2043
2046
|
var i;
|
|
2044
2047
|
for (i = 0; i < this._board_touches.length; i++) {
|
|
2045
2048
|
if (this._board_touches[i].pointerId === evt.pointerId) {
|
|
@@ -2052,7 +2055,7 @@ define([
|
|
|
2052
2055
|
},
|
|
2053
2056
|
|
|
2054
2057
|
/**
|
|
2055
|
-
* Remove all registered fingers from
|
|
2058
|
+
* Remove all registered fingers from {@link JXG.Board#_board_touches}.
|
|
2056
2059
|
* This might be necessary if too many fingers have been registered.
|
|
2057
2060
|
* @returns {JXG.Board} Reference to the board
|
|
2058
2061
|
* @private
|
|
@@ -2060,10 +2063,11 @@ define([
|
|
|
2060
2063
|
_pointerClearTouches: function() {
|
|
2061
2064
|
if (this._board_touches.length > 0) {
|
|
2062
2065
|
this.dehighlightAll();
|
|
2063
|
-
this.updateQuality = this.BOARD_QUALITY_HIGH;
|
|
2064
|
-
this.mode = this.BOARD_MODE_NONE;
|
|
2065
2066
|
}
|
|
2067
|
+
this.updateQuality = this.BOARD_QUALITY_HIGH;
|
|
2068
|
+
this.mode = this.BOARD_MODE_NONE;
|
|
2066
2069
|
this._board_touches = [];
|
|
2070
|
+
this.touches = [];
|
|
2067
2071
|
},
|
|
2068
2072
|
|
|
2069
2073
|
/**
|
|
@@ -2106,6 +2110,7 @@ define([
|
|
|
2106
2110
|
*/
|
|
2107
2111
|
pointerDownListener: function (evt, object) {
|
|
2108
2112
|
var i, j, k, pos, elements, sel,
|
|
2113
|
+
target_obj,
|
|
2109
2114
|
type = 'mouse', // Used in case of no browser
|
|
2110
2115
|
found, target;
|
|
2111
2116
|
|
|
@@ -2118,7 +2123,7 @@ define([
|
|
|
2118
2123
|
if (!object && evt.isPrimary) {
|
|
2119
2124
|
// First finger down. To be on the safe side this._board_touches is cleared.
|
|
2120
2125
|
this._pointerClearTouches();
|
|
2121
|
-
}
|
|
2126
|
+
}
|
|
2122
2127
|
|
|
2123
2128
|
if (!this.hasPointerUp) {
|
|
2124
2129
|
if (window.navigator.msPointerEnabled) { // IE10-
|
|
@@ -2156,14 +2161,14 @@ define([
|
|
|
2156
2161
|
type = this._inputDevice;
|
|
2157
2162
|
this.options.precision.hasPoint = this.options.precision[type];
|
|
2158
2163
|
|
|
2159
|
-
//
|
|
2160
|
-
//
|
|
2164
|
+
// Handling of multi touch with pointer events should be easier than the touch events.
|
|
2165
|
+
// Every pointer device has its own pointerId, e.g. the mouse
|
|
2166
|
+
// always has id 1 or 0, fingers and pens get unique ids every time a pointerDown event is fired and they will
|
|
2161
2167
|
// keep this id until a pointerUp event is fired. What we have to do here is:
|
|
2162
2168
|
// 1. collect all elements under the current pointer
|
|
2163
2169
|
// 2. run through the touches control structure
|
|
2164
2170
|
// a. look for the object collected in step 1.
|
|
2165
2171
|
// b. if an object is found, check the number of pointers. If appropriate, add the pointer.
|
|
2166
|
-
|
|
2167
2172
|
pos = this.getMousePosition(evt);
|
|
2168
2173
|
|
|
2169
2174
|
// selection
|
|
@@ -2181,45 +2186,41 @@ define([
|
|
|
2181
2186
|
elements = this.initMoveObject(pos[0], pos[1], evt, type);
|
|
2182
2187
|
}
|
|
2183
2188
|
|
|
2189
|
+
target_obj = {
|
|
2190
|
+
num: evt.pointerId,
|
|
2191
|
+
X: pos[0],
|
|
2192
|
+
Y: pos[1],
|
|
2193
|
+
Xprev: NaN,
|
|
2194
|
+
Yprev: NaN,
|
|
2195
|
+
Xstart: [],
|
|
2196
|
+
Ystart: [],
|
|
2197
|
+
Zstart: []
|
|
2198
|
+
};
|
|
2199
|
+
|
|
2184
2200
|
// If no draggable object can be found, get out here immediately
|
|
2185
2201
|
if (elements.length > 0) {
|
|
2186
2202
|
// check touches structure
|
|
2187
2203
|
target = elements[elements.length - 1];
|
|
2188
2204
|
found = false;
|
|
2205
|
+
|
|
2206
|
+
// Reminder: this.touches is the list of elements which
|
|
2207
|
+
// currently "possess" a pointer (mouse, pen, finger)
|
|
2189
2208
|
for (i = 0; i < this.touches.length; i++) {
|
|
2190
|
-
//
|
|
2209
|
+
// An element receives a further touch, i.e.
|
|
2210
|
+
// the target is already in our touches array, add the pointer to the existing touch
|
|
2191
2211
|
if (this.touches[i].obj === target) {
|
|
2192
2212
|
j = i;
|
|
2193
|
-
k = this.touches[i].targets.push(
|
|
2194
|
-
num: evt.pointerId,
|
|
2195
|
-
X: pos[0],
|
|
2196
|
-
Y: pos[1],
|
|
2197
|
-
Xprev: NaN,
|
|
2198
|
-
Yprev: NaN,
|
|
2199
|
-
Xstart: [],
|
|
2200
|
-
Ystart: [],
|
|
2201
|
-
Zstart: []
|
|
2202
|
-
}) - 1;
|
|
2203
|
-
|
|
2213
|
+
k = this.touches[i].targets.push(target_obj) - 1;
|
|
2204
2214
|
found = true;
|
|
2205
2215
|
break;
|
|
2206
2216
|
}
|
|
2207
2217
|
}
|
|
2208
|
-
|
|
2209
2218
|
if (!found) {
|
|
2219
|
+
// An new element hae been touched.
|
|
2210
2220
|
k = 0;
|
|
2211
2221
|
j = this.touches.push({
|
|
2212
2222
|
obj: target,
|
|
2213
|
-
targets: [
|
|
2214
|
-
num: evt.pointerId,
|
|
2215
|
-
X: pos[0],
|
|
2216
|
-
Y: pos[1],
|
|
2217
|
-
Xprev: NaN,
|
|
2218
|
-
Yprev: NaN,
|
|
2219
|
-
Xstart: [],
|
|
2220
|
-
Ystart: [],
|
|
2221
|
-
Zstart: []
|
|
2222
|
-
}]
|
|
2223
|
+
targets: [target_obj]
|
|
2223
2224
|
}) - 1;
|
|
2224
2225
|
}
|
|
2225
2226
|
|
|
@@ -2243,18 +2244,24 @@ define([
|
|
|
2243
2244
|
evt.stopPropagation();
|
|
2244
2245
|
}
|
|
2245
2246
|
|
|
2246
|
-
if (Env.isBrowser
|
|
2247
|
+
if (!Env.isBrowser) {
|
|
2248
|
+
return false;
|
|
2249
|
+
}
|
|
2250
|
+
if (this._getPointerInputDevice(evt) !== 'touch') {
|
|
2247
2251
|
if (this.mode === this.BOARD_MODE_NONE) {
|
|
2248
2252
|
this.mouseOriginMoveStart(evt);
|
|
2249
2253
|
}
|
|
2250
2254
|
} else {
|
|
2251
|
-
this.
|
|
2255
|
+
this._pointerStorePosition(evt);
|
|
2252
2256
|
evt.touches = this._board_touches;
|
|
2253
2257
|
|
|
2254
2258
|
// Touch events on empty areas of the board are handled here, see also touchStartListener
|
|
2255
2259
|
// 1. case: one finger. If allowed, this triggers pan with one finger
|
|
2256
|
-
if (evt.touches.length
|
|
2257
|
-
|
|
2260
|
+
if (evt.touches.length === 1 &&
|
|
2261
|
+
this.mode === this.BOARD_MODE_NONE &&
|
|
2262
|
+
this.touchStartMoveOriginOneFinger(evt)) {
|
|
2263
|
+
// Empty by purpose
|
|
2264
|
+
} else if (evt.touches.length === 2 &&
|
|
2258
2265
|
(this.mode === this.BOARD_MODE_NONE || this.mode === this.BOARD_MODE_MOVE_ORIGIN)
|
|
2259
2266
|
) {
|
|
2260
2267
|
// 2. case: two fingers: pinch to zoom or pan with two fingers needed.
|
|
@@ -2293,7 +2300,7 @@ define([
|
|
|
2293
2300
|
* @returns {Boolean}
|
|
2294
2301
|
*/
|
|
2295
2302
|
pointerMoveListener: function (evt) {
|
|
2296
|
-
var i, j, pos,
|
|
2303
|
+
var i, j, pos, touchTargets,
|
|
2297
2304
|
type = 'mouse'; // in case of no browser
|
|
2298
2305
|
|
|
2299
2306
|
if (this._getPointerInputDevice(evt) === 'touch' && !this._isPointerRegistered(evt)) {
|
|
@@ -2330,45 +2337,37 @@ define([
|
|
|
2330
2337
|
this.triggerEventHandlers(['touchmoveselecting', 'moveselecting', 'pointermoveselecting'], [evt, this.mode]);
|
|
2331
2338
|
} else if (!this.mouseOriginMove(evt)) {
|
|
2332
2339
|
if (this.mode === this.BOARD_MODE_DRAG) {
|
|
2333
|
-
//
|
|
2340
|
+
// Run through all jsxgraph elements which are touched by at least one finger.
|
|
2334
2341
|
for (i = 0; i < this.touches.length; i++) {
|
|
2342
|
+
touchTargets = this.touches[i].targets;
|
|
2335
2343
|
// Run through all touch events which have been started on this jsxgraph element.
|
|
2336
|
-
for (j = 0; j <
|
|
2337
|
-
if (
|
|
2338
|
-
if (this.touches[i].targets.length === 1) {
|
|
2339
|
-
|
|
2340
|
-
// Touch by one finger: this is possible for all elements that can be dragged
|
|
2341
|
-
this.touches[i].targets[j].X = evt.pageX;
|
|
2342
|
-
this.touches[i].targets[j].Y = evt.pageY;
|
|
2343
|
-
pos = this.getMousePosition(evt);
|
|
2344
|
-
this.moveObject(pos[0], pos[1], this.touches[i], evt, type);
|
|
2344
|
+
for (j = 0; j < touchTargets.length; j++) {
|
|
2345
|
+
if (touchTargets[j].num === evt.pointerId) {
|
|
2345
2346
|
|
|
2346
|
-
|
|
2347
|
+
pos = this.getMousePosition(evt);
|
|
2348
|
+
touchTargets[j].X = pos[0];
|
|
2349
|
+
touchTargets[j].Y = pos[1];
|
|
2347
2350
|
|
|
2351
|
+
if (touchTargets.length === 1) {
|
|
2352
|
+
// Touch by one finger: this is possible for all elements that can be dragged
|
|
2353
|
+
this.moveObject(pos[0], pos[1], this.touches[i], evt, type);
|
|
2354
|
+
} else if (touchTargets.length === 2) {
|
|
2348
2355
|
// Touch by two fingers: e.g. moving lines
|
|
2349
|
-
this.touches[i].
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
this.getMousePosition({
|
|
2354
|
-
clientX: this.touches[i].targets[0].X,
|
|
2355
|
-
clientY: this.touches[i].targets[0].Y
|
|
2356
|
-
}),
|
|
2357
|
-
this.getMousePosition({
|
|
2358
|
-
clientX: this.touches[i].targets[1].X,
|
|
2359
|
-
clientY: this.touches[i].targets[1].Y
|
|
2360
|
-
}),
|
|
2361
|
-
this.touches[i], evt);
|
|
2356
|
+
this.twoFingerMove(this.touches[i], evt.pointerId, evt);
|
|
2357
|
+
|
|
2358
|
+
touchTargets[j].Xprev = pos[0];
|
|
2359
|
+
touchTargets[j].Yprev = pos[1];
|
|
2362
2360
|
}
|
|
2363
2361
|
|
|
2364
|
-
//
|
|
2362
|
+
// There is only one pointer in the evt object, so there's no point in looking further
|
|
2365
2363
|
break;
|
|
2366
2364
|
}
|
|
2367
2365
|
}
|
|
2368
2366
|
}
|
|
2369
2367
|
} else {
|
|
2370
2368
|
if (this._getPointerInputDevice(evt) === 'touch') {
|
|
2371
|
-
this.
|
|
2369
|
+
this._pointerStorePosition(evt);
|
|
2370
|
+
|
|
2372
2371
|
if (this._board_touches.length === 2) {
|
|
2373
2372
|
evt.touches = this._board_touches;
|
|
2374
2373
|
this.gestureChangeListener(evt);
|
|
@@ -2398,21 +2397,20 @@ define([
|
|
|
2398
2397
|
* @returns {Boolean}
|
|
2399
2398
|
*/
|
|
2400
2399
|
pointerUpListener: function (evt) {
|
|
2401
|
-
var i, j, found;
|
|
2400
|
+
var i, j, found, touchTargets;
|
|
2402
2401
|
|
|
2403
2402
|
this.triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);
|
|
2404
2403
|
this.displayInfobox(false);
|
|
2405
2404
|
|
|
2406
2405
|
if (evt) {
|
|
2407
2406
|
for (i = 0; i < this.touches.length; i++) {
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
if (
|
|
2407
|
+
touchTargets = this.touches[i].targets;
|
|
2408
|
+
for (j = 0; j < touchTargets.length; j++) {
|
|
2409
|
+
if (touchTargets[j].num === evt.pointerId) {
|
|
2410
|
+
touchTargets.splice(j, 1);
|
|
2411
|
+
if (touchTargets.length === 0) {
|
|
2413
2412
|
this.touches.splice(i, 1);
|
|
2414
2413
|
}
|
|
2415
|
-
|
|
2416
2414
|
break;
|
|
2417
2415
|
}
|
|
2418
2416
|
}
|
|
@@ -2440,9 +2438,8 @@ define([
|
|
|
2440
2438
|
}
|
|
2441
2439
|
}
|
|
2442
2440
|
|
|
2443
|
-
this.
|
|
2444
|
-
|
|
2445
|
-
if (this._board_touches.length === 0) {
|
|
2441
|
+
// this._pointerRemoveTouches(evt);
|
|
2442
|
+
// if (this._board_touches.length === 0) {
|
|
2446
2443
|
if (this.hasPointerUp) {
|
|
2447
2444
|
if (window.navigator.msPointerEnabled) { // IE10-
|
|
2448
2445
|
Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);
|
|
@@ -2453,14 +2450,15 @@ define([
|
|
|
2453
2450
|
this.hasPointerUp = false;
|
|
2454
2451
|
}
|
|
2455
2452
|
|
|
2456
|
-
this.dehighlightAll();
|
|
2457
|
-
this.updateQuality = this.BOARD_QUALITY_HIGH;
|
|
2458
|
-
this.mode = this.BOARD_MODE_NONE;
|
|
2453
|
+
// this.dehighlightAll();
|
|
2454
|
+
// this.updateQuality = this.BOARD_QUALITY_HIGH;
|
|
2455
|
+
// this.mode = this.BOARD_MODE_NONE;
|
|
2459
2456
|
|
|
2460
2457
|
this.originMoveEnd();
|
|
2461
2458
|
this.update();
|
|
2462
|
-
}
|
|
2463
|
-
|
|
2459
|
+
// }
|
|
2460
|
+
// After one finger leaves the screen the gesture is stopped.
|
|
2461
|
+
this._pointerClearTouches();
|
|
2464
2462
|
return true;
|
|
2465
2463
|
},
|
|
2466
2464
|
|
|
@@ -2478,7 +2476,7 @@ define([
|
|
|
2478
2476
|
eps = this.options.precision.touch,
|
|
2479
2477
|
obj, found, targets,
|
|
2480
2478
|
evtTouches = evt[JXG.touchProperty],
|
|
2481
|
-
target;
|
|
2479
|
+
target, touchTargets;
|
|
2482
2480
|
|
|
2483
2481
|
if (!this.hasTouchEnd) {
|
|
2484
2482
|
Env.addEvent(this.document, 'touchend', this.touchEndListener, this);
|
|
@@ -2526,19 +2524,19 @@ define([
|
|
|
2526
2524
|
}
|
|
2527
2525
|
|
|
2528
2526
|
for (i = 0; i < this.touches.length; i++) {
|
|
2529
|
-
|
|
2530
|
-
|
|
2527
|
+
touchTargets = this.touches[i].targets;
|
|
2528
|
+
for (j = 0; j < touchTargets.length; j++) {
|
|
2529
|
+
touchTargets[j].num = -1;
|
|
2531
2530
|
eps = this.options.precision.touch;
|
|
2532
2531
|
|
|
2533
2532
|
do {
|
|
2534
2533
|
for (k = 0; k < evtTouches.length; k++) {
|
|
2535
2534
|
// find the new targettouches
|
|
2536
|
-
if (Math.abs(Math.pow(evtTouches[k].screenX -
|
|
2537
|
-
Math.pow(evtTouches[k].screenY -
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
this.touches[i].targets[j].Y = evtTouches[k].screenY;
|
|
2535
|
+
if (Math.abs(Math.pow(evtTouches[k].screenX - touchTargets[j].X, 2) +
|
|
2536
|
+
Math.pow(evtTouches[k].screenY - touchTargets[j].Y, 2)) < eps * eps) {
|
|
2537
|
+
touchTargets[j].num = k;
|
|
2538
|
+
touchTargets[j].X = evtTouches[k].screenX;
|
|
2539
|
+
touchTargets[j].Y = evtTouches[k].screenY;
|
|
2542
2540
|
evtTouches[k].jxg_isused = true;
|
|
2543
2541
|
break;
|
|
2544
2542
|
}
|
|
@@ -2546,13 +2544,13 @@ define([
|
|
|
2546
2544
|
|
|
2547
2545
|
eps *= 2;
|
|
2548
2546
|
|
|
2549
|
-
} while (
|
|
2547
|
+
} while (touchTargets[j].num === -1 &&
|
|
2550
2548
|
eps < this.options.precision.touchMax);
|
|
2551
2549
|
|
|
2552
|
-
if (
|
|
2550
|
+
if (touchTargets[j].num === -1) {
|
|
2553
2551
|
JXG.debug('i couldn\'t find a targettouches for target no ' + j + ' on ' + this.touches[i].obj.name + ' (' + this.touches[i].obj.id + '). Removed the target.');
|
|
2554
2552
|
JXG.debug('eps = ' + eps + ', touchMax = ' + Options.precision.touchMax);
|
|
2555
|
-
|
|
2553
|
+
touchTargets.splice(i, 1);
|
|
2556
2554
|
}
|
|
2557
2555
|
|
|
2558
2556
|
}
|
|
@@ -2578,20 +2576,22 @@ define([
|
|
|
2578
2576
|
elements = this.initMoveObject(pos[0], pos[1], evt, 'touch');
|
|
2579
2577
|
if (elements.length !== 0) {
|
|
2580
2578
|
obj = elements[elements.length - 1];
|
|
2579
|
+
target = {num: i,
|
|
2580
|
+
X: evtTouches[i].screenX,
|
|
2581
|
+
Y: evtTouches[i].screenY,
|
|
2582
|
+
Xprev: NaN,
|
|
2583
|
+
Yprev: NaN,
|
|
2584
|
+
Xstart: [],
|
|
2585
|
+
Ystart: [],
|
|
2586
|
+
Zstart: []
|
|
2587
|
+
};
|
|
2581
2588
|
|
|
2582
2589
|
if (Type.isPoint(obj) ||
|
|
2583
2590
|
obj.elementClass === Const.OBJECT_CLASS_TEXT ||
|
|
2584
2591
|
obj.type === Const.OBJECT_TYPE_TICKS ||
|
|
2585
2592
|
obj.type === Const.OBJECT_TYPE_IMAGE) {
|
|
2586
|
-
//
|
|
2587
|
-
targets = [
|
|
2588
|
-
X: evtTouches[i].screenX,
|
|
2589
|
-
Y: evtTouches[i].screenY,
|
|
2590
|
-
Xprev: NaN,
|
|
2591
|
-
Yprev: NaN,
|
|
2592
|
-
Xstart: [],
|
|
2593
|
-
Ystart: [],
|
|
2594
|
-
Zstart: [] }];
|
|
2593
|
+
// It's a point, so it's single touch, so we just push it to our touches
|
|
2594
|
+
targets = [target];
|
|
2595
2595
|
|
|
2596
2596
|
// For the UNDO/REDO of object moves
|
|
2597
2597
|
this.saveStartPos(obj, targets[0]);
|
|
@@ -2611,15 +2611,6 @@ define([
|
|
|
2611
2611
|
found = true;
|
|
2612
2612
|
// only add it, if we don't have two targets in there already
|
|
2613
2613
|
if (this.touches[j].targets.length === 1) {
|
|
2614
|
-
target = {num: i,
|
|
2615
|
-
X: evtTouches[i].screenX,
|
|
2616
|
-
Y: evtTouches[i].screenY,
|
|
2617
|
-
Xprev: NaN,
|
|
2618
|
-
Yprev: NaN,
|
|
2619
|
-
Xstart: [],
|
|
2620
|
-
Ystart: [],
|
|
2621
|
-
Zstart: [] };
|
|
2622
|
-
|
|
2623
2614
|
// For the UNDO/REDO of object moves
|
|
2624
2615
|
this.saveStartPos(obj, target);
|
|
2625
2616
|
this.touches[j].targets.push(target);
|
|
@@ -2633,14 +2624,7 @@ define([
|
|
|
2633
2624
|
// IF there is a second touch targetting this line, we will find it later on, and then add it to
|
|
2634
2625
|
// the touches control object.
|
|
2635
2626
|
if (!found) {
|
|
2636
|
-
targets = [
|
|
2637
|
-
X: evtTouches[i].screenX,
|
|
2638
|
-
Y: evtTouches[i].screenY,
|
|
2639
|
-
Xprev: NaN,
|
|
2640
|
-
Yprev: NaN,
|
|
2641
|
-
Xstart: [],
|
|
2642
|
-
Ystart: [],
|
|
2643
|
-
Zstart: [] }];
|
|
2627
|
+
targets = [target];
|
|
2644
2628
|
|
|
2645
2629
|
// For the UNDO/REDO of object moves
|
|
2646
2630
|
this.saveStartPos(obj, targets[0]);
|
|
@@ -2687,7 +2671,8 @@ define([
|
|
|
2687
2671
|
* @returns {Boolean}
|
|
2688
2672
|
*/
|
|
2689
2673
|
touchMoveListener: function (evt) {
|
|
2690
|
-
var i, pos1, pos2,
|
|
2674
|
+
var i, pos1, pos2,
|
|
2675
|
+
touchTargets,
|
|
2691
2676
|
evtTouches = evt[JXG.touchProperty];
|
|
2692
2677
|
|
|
2693
2678
|
if (!this.checkFrameRate(evt)) {
|
|
@@ -2724,40 +2709,52 @@ define([
|
|
|
2724
2709
|
// Runs over through all elements which are touched
|
|
2725
2710
|
// by at least one finger.
|
|
2726
2711
|
for (i = 0; i < this.touches.length; i++) {
|
|
2727
|
-
|
|
2712
|
+
touchTargets = this.touches[i].targets;
|
|
2713
|
+
if (touchTargets.length === 1) {
|
|
2714
|
+
|
|
2715
|
+
|
|
2728
2716
|
// Touch by one finger: this is possible for all elements that can be dragged
|
|
2729
|
-
if (evtTouches[
|
|
2730
|
-
pos1 = this.getMousePosition(evt,
|
|
2717
|
+
if (evtTouches[touchTargets[0].num]) {
|
|
2718
|
+
pos1 = this.getMousePosition(evt, touchTargets[0].num);
|
|
2731
2719
|
if (pos1[0] < 0 || pos1[0] > this.canvasWidth ||
|
|
2732
2720
|
pos1[1] < 0 || pos1[1] > this.canvasHeight) {
|
|
2733
2721
|
return;
|
|
2734
2722
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2723
|
+
touchTargets[0].X = pos1[0];
|
|
2724
|
+
touchTargets[0].Y = pos1[1];
|
|
2737
2725
|
this.moveObject(pos1[0], pos1[1], this.touches[i], evt, 'touch');
|
|
2738
2726
|
}
|
|
2739
2727
|
|
|
2740
|
-
} else if (
|
|
2741
|
-
|
|
2742
|
-
|
|
2728
|
+
} else if (touchTargets.length === 2 &&
|
|
2729
|
+
touchTargets[0].num > -1 &&
|
|
2730
|
+
touchTargets[1].num > -1) {
|
|
2731
|
+
|
|
2743
2732
|
// Touch by two fingers: moving lines, ...
|
|
2744
|
-
if (evtTouches[
|
|
2745
|
-
evtTouches[
|
|
2733
|
+
if (evtTouches[touchTargets[0].num] &&
|
|
2734
|
+
evtTouches[touchTargets[1].num]) {
|
|
2746
2735
|
|
|
2747
2736
|
// Get coordinates of the two touches
|
|
2748
|
-
pos1 = this.getMousePosition(evt,
|
|
2749
|
-
pos2 = this.getMousePosition(evt,
|
|
2737
|
+
pos1 = this.getMousePosition(evt, touchTargets[0].num);
|
|
2738
|
+
pos2 = this.getMousePosition(evt, touchTargets[1].num);
|
|
2750
2739
|
if (pos1[0] < 0 || pos1[0] > this.canvasWidth ||
|
|
2751
2740
|
pos1[1] < 0 || pos1[1] > this.canvasHeight ||
|
|
2752
2741
|
pos2[0] < 0 || pos2[0] > this.canvasWidth ||
|
|
2753
2742
|
pos2[1] < 0 || pos2[1] > this.canvasHeight) {
|
|
2754
2743
|
return;
|
|
2755
2744
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2745
|
+
|
|
2746
|
+
touchTargets[0].X = pos1[0];
|
|
2747
|
+
touchTargets[0].Y = pos1[1];
|
|
2748
|
+
touchTargets[1].X = pos2[0];
|
|
2749
|
+
touchTargets[1].Y = pos2[1];
|
|
2750
|
+
|
|
2751
|
+
this.twoFingerMove(this.touches[i], touchTargets[0].num, evt);
|
|
2752
|
+
this.twoFingerMove(this.touches[i], touchTargets[1].num);
|
|
2753
|
+
|
|
2754
|
+
touchTargets[0].Xprev = pos1[0];
|
|
2755
|
+
touchTargets[0].Yprev = pos1[1];
|
|
2756
|
+
touchTargets[1].Xprev = pos2[0];
|
|
2757
|
+
touchTargets[1].Yprev = pos2[1];
|
|
2761
2758
|
}
|
|
2762
2759
|
}
|
|
2763
2760
|
}
|
|
@@ -2792,7 +2789,8 @@ define([
|
|
|
2792
2789
|
var i, j, k,
|
|
2793
2790
|
eps = this.options.precision.touch,
|
|
2794
2791
|
tmpTouches = [], found, foundNumber,
|
|
2795
|
-
evtTouches = evt && evt[JXG.touchProperty]
|
|
2792
|
+
evtTouches = evt && evt[JXG.touchProperty],
|
|
2793
|
+
touchTargets;
|
|
2796
2794
|
|
|
2797
2795
|
this.triggerEventHandlers(['touchend', 'up'], [evt]);
|
|
2798
2796
|
this.displayInfobox(false);
|
|
@@ -2828,15 +2826,16 @@ define([
|
|
|
2828
2826
|
// could all targets of the current this.touches.obj be assigned to targettouches?
|
|
2829
2827
|
found = false;
|
|
2830
2828
|
foundNumber = 0;
|
|
2829
|
+
touchTargets = tmpTouches[i].targets;
|
|
2831
2830
|
|
|
2832
|
-
for (j = 0; j <
|
|
2833
|
-
|
|
2831
|
+
for (j = 0; j < touchTargets.length; j++) {
|
|
2832
|
+
touchTargets[j].found = false;
|
|
2834
2833
|
for (k = 0; k < evtTouches.length; k++) {
|
|
2835
|
-
if (Math.abs(Math.pow(evtTouches[k].screenX -
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2834
|
+
if (Math.abs(Math.pow(evtTouches[k].screenX - touchTargets[j].X, 2) + Math.pow(evtTouches[k].screenY - touchTargets[j].Y, 2)) < eps * eps) {
|
|
2835
|
+
touchTargets[j].found = true;
|
|
2836
|
+
touchTargets[j].num = k;
|
|
2837
|
+
touchTargets[j].X = evtTouches[k].screenX;
|
|
2838
|
+
touchTargets[j].Y = evtTouches[k].screenY;
|
|
2840
2839
|
foundNumber += 1;
|
|
2841
2840
|
break;
|
|
2842
2841
|
}
|
|
@@ -2844,9 +2843,9 @@ define([
|
|
|
2844
2843
|
}
|
|
2845
2844
|
|
|
2846
2845
|
if (Type.isPoint(tmpTouches[i].obj)) {
|
|
2847
|
-
found = (
|
|
2846
|
+
found = (touchTargets[0] && touchTargets[0].found);
|
|
2848
2847
|
} else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_LINE) {
|
|
2849
|
-
found = (
|
|
2848
|
+
found = (touchTargets[0] && touchTargets[0].found) || (touchTargets[1] && touchTargets[1].found);
|
|
2850
2849
|
} else if (tmpTouches[i].obj.elementClass === Const.OBJECT_CLASS_CIRCLE) {
|
|
2851
2850
|
found = foundNumber === 1 || foundNumber === 3;
|
|
2852
2851
|
}
|
|
@@ -2858,17 +2857,17 @@ define([
|
|
|
2858
2857
|
targets: []
|
|
2859
2858
|
});
|
|
2860
2859
|
|
|
2861
|
-
for (j = 0; j <
|
|
2862
|
-
if (
|
|
2860
|
+
for (j = 0; j < touchTargets.length; j++) {
|
|
2861
|
+
if (touchTargets[j].found) {
|
|
2863
2862
|
this.touches[this.touches.length - 1].targets.push({
|
|
2864
|
-
num:
|
|
2865
|
-
X:
|
|
2866
|
-
Y:
|
|
2863
|
+
num: touchTargets[j].num,
|
|
2864
|
+
X: touchTargets[j].screenX,
|
|
2865
|
+
Y: touchTargets[j].screenY,
|
|
2867
2866
|
Xprev: NaN,
|
|
2868
2867
|
Yprev: NaN,
|
|
2869
|
-
Xstart:
|
|
2870
|
-
Ystart:
|
|
2871
|
-
Zstart:
|
|
2868
|
+
Xstart: touchTargets[j].Xstart,
|
|
2869
|
+
Ystart: touchTargets[j].Ystart,
|
|
2870
|
+
Zstart: touchTargets[j].Zstart
|
|
2872
2871
|
});
|
|
2873
2872
|
}
|
|
2874
2873
|
}
|
|
@@ -2958,6 +2957,7 @@ define([
|
|
|
2958
2957
|
this.mode = this.BOARD_MODE_NONE;
|
|
2959
2958
|
result = true;
|
|
2960
2959
|
} else {
|
|
2960
|
+
/** @ignore */
|
|
2961
2961
|
this.mouse = {
|
|
2962
2962
|
obj: null,
|
|
2963
2963
|
targets: [{
|
|
@@ -3082,6 +3082,7 @@ define([
|
|
|
3082
3082
|
}
|
|
3083
3083
|
|
|
3084
3084
|
// release dragged mouse object
|
|
3085
|
+
/** @ignore */
|
|
3085
3086
|
this.mouse = null;
|
|
3086
3087
|
},
|
|
3087
3088
|
|
|
@@ -3110,6 +3111,7 @@ define([
|
|
|
3110
3111
|
evt.preventDefault();
|
|
3111
3112
|
return false;
|
|
3112
3113
|
},
|
|
3114
|
+
|
|
3113
3115
|
/**
|
|
3114
3116
|
* Allow moving of JSXGraph elements with arrow keys
|
|
3115
3117
|
* and zooming of the construction with + / -.
|
|
@@ -3126,10 +3128,15 @@ define([
|
|
|
3126
3128
|
*/
|
|
3127
3129
|
keyDownListener: function (evt) {
|
|
3128
3130
|
var id_node = evt.target.id,
|
|
3129
|
-
id, el,
|
|
3131
|
+
id, el, res,
|
|
3132
|
+
sX = 0,
|
|
3133
|
+
sY = 0,
|
|
3134
|
+
// dx, dy are provided in screen units and
|
|
3135
|
+
// are converted to user coordinates
|
|
3130
3136
|
dx = Type.evaluate(this.attr.keyboard.dx) / this.unitX,
|
|
3131
3137
|
dy = Type.evaluate(this.attr.keyboard.dy) / this.unitY,
|
|
3132
3138
|
doZoom = false,
|
|
3139
|
+
done = true,
|
|
3133
3140
|
dir, actPos;
|
|
3134
3141
|
|
|
3135
3142
|
if (!this.attr.keyboard.enabled || id_node === '') {
|
|
@@ -3158,8 +3165,44 @@ define([
|
|
|
3158
3165
|
this.clickLeftArrow();
|
|
3159
3166
|
} else if (evt.keyCode === 39) { // right
|
|
3160
3167
|
this.clickRightArrow();
|
|
3168
|
+
} else {
|
|
3169
|
+
done = false;
|
|
3161
3170
|
}
|
|
3162
3171
|
} else {
|
|
3172
|
+
// Adapt dx, dy to snapToGrid and attractToGrid
|
|
3173
|
+
// snapToGrid has priority.
|
|
3174
|
+
if (Type.exists(el.visProp)) {
|
|
3175
|
+
if (Type.exists(el.visProp.snaptogrid) &&
|
|
3176
|
+
el.visProp.snaptogrid &&
|
|
3177
|
+
Type.evaluate(el.visProp.snapsizex) &&
|
|
3178
|
+
Type.evaluate(el.visProp.snapsizey)) {
|
|
3179
|
+
|
|
3180
|
+
// Adapt dx, dy such that snapToGrid is possible
|
|
3181
|
+
res = el.getSnapSizes();
|
|
3182
|
+
sX = res[0];
|
|
3183
|
+
sY = res[1];
|
|
3184
|
+
dx = Math.max(sX, dx);
|
|
3185
|
+
dy = Math.max(sY, dy);
|
|
3186
|
+
|
|
3187
|
+
} else if (Type.exists(el.visProp.attracttogrid) &&
|
|
3188
|
+
el.visProp.attracttogrid &&
|
|
3189
|
+
Type.evaluate(el.visProp.attractordistance) &&
|
|
3190
|
+
Type.evaluate(el.visProp.attractorunit)) {
|
|
3191
|
+
|
|
3192
|
+
// Adapt dx, dy such that attractToGrid is possible
|
|
3193
|
+
sX = 1.1 * Type.evaluate(el.visProp.attractordistance);
|
|
3194
|
+
sY = sX;
|
|
3195
|
+
|
|
3196
|
+
if (Type.evaluate(el.visProp.attractorunit) === 'screen') {
|
|
3197
|
+
sX /= this.unitX;
|
|
3198
|
+
sY /= this.unitX;
|
|
3199
|
+
}
|
|
3200
|
+
dx = Math.max(sX, dx);
|
|
3201
|
+
dy = Math.max(sY, dy);
|
|
3202
|
+
}
|
|
3203
|
+
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3163
3206
|
if (evt.keyCode === 38) { // up
|
|
3164
3207
|
dir = [0, dy];
|
|
3165
3208
|
} else if (evt.keyCode === 40) { // down
|
|
@@ -3174,9 +3217,12 @@ define([
|
|
|
3174
3217
|
this.zoomIn();
|
|
3175
3218
|
} else if (doZoom && evt.key === '-') { // -
|
|
3176
3219
|
this.zoomOut();
|
|
3177
|
-
} else if (doZoom && evt.key === 'o') {
|
|
3220
|
+
} else if (doZoom && evt.key === 'o') { // o
|
|
3178
3221
|
this.zoom100();
|
|
3222
|
+
} else {
|
|
3223
|
+
done = false;
|
|
3179
3224
|
}
|
|
3225
|
+
|
|
3180
3226
|
if (dir && el.isDraggable &&
|
|
3181
3227
|
el.visPropCalc.visible &&
|
|
3182
3228
|
((this.geonextCompatibilityMode &&
|
|
@@ -3193,11 +3239,18 @@ define([
|
|
|
3193
3239
|
// For coordsElement setPosition has to call setPositionDirectly.
|
|
3194
3240
|
// Otherwise the position is set by a translation.
|
|
3195
3241
|
el.setPosition(JXG.COORDS_BY_USER, dir);
|
|
3242
|
+
if (Type.exists(el.coords)) {
|
|
3243
|
+
this.updateInfobox(el);
|
|
3244
|
+
}
|
|
3245
|
+
this.triggerEventHandlers(['hit'], [evt, el]);
|
|
3196
3246
|
}
|
|
3197
3247
|
}
|
|
3198
3248
|
|
|
3199
3249
|
this.update();
|
|
3200
3250
|
|
|
3251
|
+
if (done) {
|
|
3252
|
+
evt.preventDefault();
|
|
3253
|
+
}
|
|
3201
3254
|
return true;
|
|
3202
3255
|
},
|
|
3203
3256
|
|
|
@@ -3224,6 +3277,10 @@ define([
|
|
|
3224
3277
|
if (Type.exists(el.highlight)) {
|
|
3225
3278
|
el.highlight(true);
|
|
3226
3279
|
}
|
|
3280
|
+
if (Type.exists(el.coords)) {
|
|
3281
|
+
this.updateInfobox(el);
|
|
3282
|
+
}
|
|
3283
|
+
this.triggerEventHandlers(['hit'], [evt, el]);
|
|
3227
3284
|
},
|
|
3228
3285
|
|
|
3229
3286
|
/**
|
|
@@ -3236,7 +3293,7 @@ define([
|
|
|
3236
3293
|
*
|
|
3237
3294
|
* @param {Event} evt The browser's event object
|
|
3238
3295
|
*/
|
|
3239
|
-
|
|
3296
|
+
keyFocusOutListener: function (evt) {
|
|
3240
3297
|
if (!this.attr.keyboard.enabled) {
|
|
3241
3298
|
return false;
|
|
3242
3299
|
}
|
|
@@ -3246,6 +3303,7 @@ define([
|
|
|
3246
3303
|
// id = id_node.replace(this.containerObj.id + '_', '');
|
|
3247
3304
|
// el = this.select(id);
|
|
3248
3305
|
this.dehighlightAll();
|
|
3306
|
+
this.displayInfobox(false);
|
|
3249
3307
|
},
|
|
3250
3308
|
|
|
3251
3309
|
/**
|
|
@@ -3284,7 +3342,7 @@ define([
|
|
|
3284
3342
|
|
|
3285
3343
|
// If bounding box is not yet initialized, do it now.
|
|
3286
3344
|
if (isNaN(this.getBoundingBox()[0])) {
|
|
3287
|
-
this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio);
|
|
3345
|
+
this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'keep');
|
|
3288
3346
|
}
|
|
3289
3347
|
|
|
3290
3348
|
// Do nothing if the dimension did not change since being visible
|
|
@@ -3300,7 +3358,7 @@ define([
|
|
|
3300
3358
|
this._prevDim = {
|
|
3301
3359
|
w: w,
|
|
3302
3360
|
h: h
|
|
3303
|
-
}
|
|
3361
|
+
};
|
|
3304
3362
|
},
|
|
3305
3363
|
|
|
3306
3364
|
/**
|
|
@@ -3424,13 +3482,12 @@ define([
|
|
|
3424
3482
|
this.intersectionObserver = new IntersectionObserver(function(entries) {
|
|
3425
3483
|
// If bounding box is not yet initialized, do it now.
|
|
3426
3484
|
if (isNaN(that.getBoundingBox()[0])) {
|
|
3427
|
-
that.setBoundingBox(that.attr.boundingbox, that.keepaspectratio);
|
|
3428
3485
|
that.updateContainerDims();
|
|
3429
3486
|
}
|
|
3430
3487
|
}, options);
|
|
3431
3488
|
this.intersectionObserver.observe(that.containerObj);
|
|
3432
3489
|
} catch (err) {
|
|
3433
|
-
console.log('
|
|
3490
|
+
console.log('JSXGraph: IntersectionObserver not available in this browser.');
|
|
3434
3491
|
}
|
|
3435
3492
|
},
|
|
3436
3493
|
|
|
@@ -3465,7 +3522,7 @@ define([
|
|
|
3465
3522
|
* Infobox close to points in which the points' coordinates are displayed.
|
|
3466
3523
|
* This is simply a JXG.Text element. Access through board.infobox.
|
|
3467
3524
|
* Uses CSS class .JXGinfobox.
|
|
3468
|
-
* @type
|
|
3525
|
+
* @type JXG.Text
|
|
3469
3526
|
*
|
|
3470
3527
|
*/
|
|
3471
3528
|
this.infobox = this.create('text', [0, 0, '0,0'], attr);
|
|
@@ -3657,11 +3714,11 @@ define([
|
|
|
3657
3714
|
* // Shorter version:
|
|
3658
3715
|
* //somePoint = board.create('point', a, {name:'SomePoint',size:4});
|
|
3659
3716
|
* });
|
|
3660
|
-
*
|
|
3717
|
+
*
|
|
3661
3718
|
* })();
|
|
3662
3719
|
*
|
|
3663
3720
|
* </script><pre>
|
|
3664
|
-
*
|
|
3721
|
+
*
|
|
3665
3722
|
* @see JXG.Board#getScrCoordsOfMouse
|
|
3666
3723
|
* @see JXG.Board#getAllUnderMouse
|
|
3667
3724
|
*/
|
|
@@ -3783,7 +3840,7 @@ define([
|
|
|
3783
3840
|
addConditions: function (str) {
|
|
3784
3841
|
var term, m, left, right, name, el, property,
|
|
3785
3842
|
functions = [],
|
|
3786
|
-
plaintext = 'var el, x, y, c, rgbo;\n',
|
|
3843
|
+
// plaintext = 'var el, x, y, c, rgbo;\n',
|
|
3787
3844
|
i = str.indexOf('<data>'),
|
|
3788
3845
|
j = str.indexOf('<' + '/data>'),
|
|
3789
3846
|
|
|
@@ -3867,7 +3924,7 @@ define([
|
|
|
3867
3924
|
if (!Type.exists(this.elementsByName[name])) {
|
|
3868
3925
|
JXG.debug("debug conditions: |" + name + "| undefined");
|
|
3869
3926
|
} else {
|
|
3870
|
-
plaintext += "el = this.objects[\"" + el.id + "\"];\n";
|
|
3927
|
+
// plaintext += "el = this.objects[\"" + el.id + "\"];\n";
|
|
3871
3928
|
|
|
3872
3929
|
switch (property) {
|
|
3873
3930
|
case 'x':
|
|
@@ -3994,9 +4051,7 @@ define([
|
|
|
3994
4051
|
tr = (bb[1] - y) / (bb[1] - bb[3]);
|
|
3995
4052
|
}
|
|
3996
4053
|
|
|
3997
|
-
this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio);
|
|
3998
|
-
this.zoomX *= zX;
|
|
3999
|
-
this.zoomY *= zY;
|
|
4054
|
+
this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio, 'update');
|
|
4000
4055
|
return this.applyZoom();
|
|
4001
4056
|
},
|
|
4002
4057
|
|
|
@@ -4027,25 +4082,32 @@ define([
|
|
|
4027
4082
|
tr = (bb[1] - y) / (bb[1] - bb[3]);
|
|
4028
4083
|
}
|
|
4029
4084
|
|
|
4030
|
-
this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio);
|
|
4031
|
-
this.zoomX /= zX;
|
|
4032
|
-
this.zoomY /= zY;
|
|
4085
|
+
this.setBoundingBox([bb[0] + dX * lr, bb[1] - dY * tr, bb[2] - dX * (1 - lr), bb[3] + dY * (1 - tr)], this.keepaspectratio, 'update');
|
|
4033
4086
|
|
|
4034
4087
|
return this.applyZoom();
|
|
4035
4088
|
},
|
|
4036
4089
|
|
|
4037
4090
|
/**
|
|
4038
|
-
*
|
|
4091
|
+
* Reset the zoom level to the original zoom level from initBoard();
|
|
4092
|
+
* Additionally, if the board as been initialized with a boundingBox (which is the default),
|
|
4093
|
+
* restore the viewport to the original viewport during initialization. Otherwise,
|
|
4094
|
+
* (i.e. if the board as been initialized with unitX/Y and originX/Y),
|
|
4095
|
+
* just set the zoom level to 100%.
|
|
4096
|
+
*
|
|
4039
4097
|
* @returns {JXG.Board} Reference to the board
|
|
4040
4098
|
*/
|
|
4041
4099
|
zoom100: function () {
|
|
4042
|
-
var bb
|
|
4043
|
-
dX = (bb[2] - bb[0]) * (1.0 - this.zoomX) * 0.5,
|
|
4044
|
-
dY = (bb[1] - bb[3]) * (1.0 - this.zoomY) * 0.5;
|
|
4100
|
+
var bb, dX, dY;
|
|
4045
4101
|
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4102
|
+
if (Type.exists(this.attr.boundingbox)) {
|
|
4103
|
+
this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'reset');
|
|
4104
|
+
} else {
|
|
4105
|
+
// Board has been set up with unitX/Y and originX/Y
|
|
4106
|
+
bb = this.getBoundingBox();
|
|
4107
|
+
dX = (bb[2] - bb[0]) * (1.0 - this.zoomX) * 0.5;
|
|
4108
|
+
dY = (bb[1] - bb[3]) * (1.0 - this.zoomY) * 0.5;
|
|
4109
|
+
this.setBoundingBox([bb[0] + dX, bb[1] - dY, bb[2] - dX, bb[3] + dY], this.keepaspectratio, 'reset');
|
|
4110
|
+
}
|
|
4049
4111
|
return this.applyZoom();
|
|
4050
4112
|
},
|
|
4051
4113
|
|
|
@@ -4082,10 +4144,7 @@ define([
|
|
|
4082
4144
|
borderX = border / this.unitX;
|
|
4083
4145
|
borderY = border / this.unitY;
|
|
4084
4146
|
|
|
4085
|
-
this.
|
|
4086
|
-
this.zoomY = 1.0;
|
|
4087
|
-
|
|
4088
|
-
this.setBoundingBox([minX - borderX, maxY + borderY, maxX + borderX, minY - borderY], this.keepaspectratio);
|
|
4147
|
+
this.setBoundingBox([minX - borderX, maxY + borderY, maxX + borderX, minY - borderY], this.keepaspectratio, 'update');
|
|
4089
4148
|
|
|
4090
4149
|
return this.applyZoom();
|
|
4091
4150
|
},
|
|
@@ -4118,53 +4177,12 @@ define([
|
|
|
4118
4177
|
}
|
|
4119
4178
|
|
|
4120
4179
|
if (Type.isArray(newBBox)) {
|
|
4121
|
-
this.zoomX = 1.0;
|
|
4122
|
-
this.zoomY = 1.0;
|
|
4123
4180
|
cx = 0.5 * (newBBox[0] + newBBox[2]);
|
|
4124
4181
|
cy = 0.5 * (newBBox[1] + newBBox[3]);
|
|
4125
4182
|
dx = 1.5 * (newBBox[2] - newBBox[0]) * 0.5;
|
|
4126
4183
|
dy = 1.5 * (newBBox[1] - newBBox[3]) * 0.5;
|
|
4127
4184
|
d = Math.max(dx, dy);
|
|
4128
|
-
this.setBoundingBox([cx - d, cy + d, cx + d, cy - d], this.keepaspectratio);
|
|
4129
|
-
}
|
|
4130
|
-
|
|
4131
|
-
return this;
|
|
4132
|
-
},
|
|
4133
|
-
|
|
4134
|
-
zoomElementsOld: function (elements) {
|
|
4135
|
-
var i, j, e, box,
|
|
4136
|
-
newBBox = [0, 0, 0, 0],
|
|
4137
|
-
dir = [1, -1, -1, 1];
|
|
4138
|
-
|
|
4139
|
-
if (!Type.isArray(elements) || elements.length === 0) {
|
|
4140
|
-
return this;
|
|
4141
|
-
}
|
|
4142
|
-
|
|
4143
|
-
for (i = 0; i < elements.length; i++) {
|
|
4144
|
-
e = this.select(elements[i]);
|
|
4145
|
-
|
|
4146
|
-
box = e.bounds();
|
|
4147
|
-
if (Type.isArray(box)) {
|
|
4148
|
-
if (Type.isArray(newBBox)) {
|
|
4149
|
-
for (j = 0; j < 4; j++) {
|
|
4150
|
-
if (dir[j] * box[j] < dir[j] * newBBox[j]) {
|
|
4151
|
-
newBBox[j] = box[j];
|
|
4152
|
-
}
|
|
4153
|
-
}
|
|
4154
|
-
} else {
|
|
4155
|
-
newBBox = box;
|
|
4156
|
-
}
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
|
|
4160
|
-
if (Type.isArray(newBBox)) {
|
|
4161
|
-
for (j = 0; j < 4; j++) {
|
|
4162
|
-
newBBox[j] -= dir[j];
|
|
4163
|
-
}
|
|
4164
|
-
|
|
4165
|
-
this.zoomX = 1.0;
|
|
4166
|
-
this.zoomY = 1.0;
|
|
4167
|
-
this.setBoundingBox(newBBox, this.keepaspectratio);
|
|
4185
|
+
this.setBoundingBox([cx - d, cy + d, cx + d, cy - d], this.keepaspectratio, 'update');
|
|
4168
4186
|
}
|
|
4169
4187
|
|
|
4170
4188
|
return this;
|
|
@@ -4381,33 +4399,38 @@ define([
|
|
|
4381
4399
|
* @returns {JXG.Board} Reference to the board
|
|
4382
4400
|
*/
|
|
4383
4401
|
resizeContainer: function (canvasWidth, canvasHeight, dontset, dontSetBoundingBox) {
|
|
4384
|
-
var
|
|
4385
|
-
|
|
4386
|
-
|
|
4402
|
+
var box;
|
|
4403
|
+
// w, h, cx, cy;
|
|
4404
|
+
// box_act,
|
|
4405
|
+
// shift_x = 0,
|
|
4406
|
+
// shift_y = 0;
|
|
4407
|
+
|
|
4408
|
+
if (!dontSetBoundingBox) {
|
|
4409
|
+
// box_act = this.getBoundingBox(); // This is the actual bounding box.
|
|
4410
|
+
box = this.getBoundingBox(); // This is the actual bounding box.
|
|
4411
|
+
}
|
|
4387
4412
|
|
|
4388
4413
|
this.canvasWidth = parseFloat(canvasWidth);
|
|
4389
4414
|
this.canvasHeight = parseFloat(canvasHeight);
|
|
4390
4415
|
|
|
4391
|
-
if (!dontSetBoundingBox) {
|
|
4392
|
-
|
|
4393
|
-
box = this.attr.boundingbox; // This is the intended bounding box.
|
|
4394
|
-
// The shift values compensate the follow-up
|
|
4395
|
-
// correction in setBoundingBox in case this.keepaspectratio==true
|
|
4396
|
-
// Otherwise, shift_x and shift_y will be zero.
|
|
4397
|
-
shift_x = box_act[0] - box[0];
|
|
4398
|
-
shift_y = box_act[1] - box[1];
|
|
4416
|
+
// if (!dontSetBoundingBox) {
|
|
4417
|
+
// box = this.attr.boundingbox; // This is the intended bounding box.
|
|
4399
4418
|
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4419
|
+
// // The shift values compensate the follow-up correction
|
|
4420
|
+
// // in setBoundingBox in case of "this.keepaspectratio==true"
|
|
4421
|
+
// // Otherwise, shift_x and shift_y will be zero.
|
|
4422
|
+
// // Obsolet since setBoundingBox centers in case of "this.keepaspectratio==true".
|
|
4423
|
+
// // shift_x = box_act[0] - box[0] / this.zoomX;
|
|
4424
|
+
// // shift_y = box_act[1] - box[1] / this.zoomY;
|
|
4404
4425
|
|
|
4405
|
-
|
|
4406
|
-
|
|
4426
|
+
// cx = (box[2] + box[0]) * 0.5; // + shift_x;
|
|
4427
|
+
// cy = (box[3] + box[1]) * 0.5; // + shift_y;
|
|
4407
4428
|
|
|
4408
|
-
|
|
4409
|
-
|
|
4429
|
+
// w = (box[2] - box[0]) * 0.5 / this.zoomX;
|
|
4430
|
+
// h = (box[1] - box[3]) * 0.5 / this.zoomY;
|
|
4410
4431
|
|
|
4432
|
+
// box = [cx - w, cy + h, cx + w, cy - h];
|
|
4433
|
+
// }
|
|
4411
4434
|
|
|
4412
4435
|
if (!dontset) {
|
|
4413
4436
|
this.containerObj.style.width = (this.canvasWidth) + 'px';
|
|
@@ -4416,7 +4439,7 @@ define([
|
|
|
4416
4439
|
this.renderer.resize(this.canvasWidth, this.canvasHeight);
|
|
4417
4440
|
|
|
4418
4441
|
if (!dontSetBoundingBox) {
|
|
4419
|
-
this.setBoundingBox(box, this.keepaspectratio);
|
|
4442
|
+
this.setBoundingBox(box, this.keepaspectratio, 'keep');
|
|
4420
4443
|
}
|
|
4421
4444
|
|
|
4422
4445
|
return this;
|
|
@@ -4523,13 +4546,13 @@ define([
|
|
|
4523
4546
|
|
|
4524
4547
|
for (el = 0; el < this.objectsList.length; el++) {
|
|
4525
4548
|
pEl = this.objectsList[el];
|
|
4526
|
-
if (this.needsFullUpdate && pEl.elementClass
|
|
4549
|
+
if (this.needsFullUpdate && pEl.elementClass === Const.OBJECT_CLASS_TEXT) {
|
|
4527
4550
|
pEl.updateSize();
|
|
4528
4551
|
}
|
|
4529
4552
|
|
|
4530
4553
|
// For updates of an element we distinguish if the dragged element is updated or
|
|
4531
4554
|
// other elements are updated.
|
|
4532
|
-
// The difference lies in the treatment of gliders.
|
|
4555
|
+
// The difference lies in the treatment of gliders and points based on transformations.
|
|
4533
4556
|
pEl.update(!Type.exists(drag) || pEl.id !== drag.id)
|
|
4534
4557
|
.updateVisibility();
|
|
4535
4558
|
}
|
|
@@ -4826,6 +4849,7 @@ define([
|
|
|
4826
4849
|
for (i = 0; i < parents.length; i++) {
|
|
4827
4850
|
if (Type.isString(parents[i]) &&
|
|
4828
4851
|
!(elementType === 'text' && i === 2) &&
|
|
4852
|
+
!(elementType === 'solidofrevolution3d' && i === 2) &&
|
|
4829
4853
|
!((elementType === 'input' || elementType === 'checkbox' || elementType === 'button') &&
|
|
4830
4854
|
(i === 2 || i === 3)) &&
|
|
4831
4855
|
!(elementType === 'curve' && i > 0) // Allow curve plots with jessiecode
|
|
@@ -4903,15 +4927,21 @@ define([
|
|
|
4903
4927
|
* @param {Array} bbox New bounding box [x1,y1,x2,y2]
|
|
4904
4928
|
* @param {Boolean} [keepaspectratio=false] If set to true, the aspect ratio will be 1:1, but
|
|
4905
4929
|
* the resulting viewport may be larger.
|
|
4930
|
+
* @param {String} [setZoom='reset'] Reset, keep or update the zoom level of the board. 'reset'
|
|
4931
|
+
* sets {@link JXG.Board#zoomX} and {@link JXG.Board#zoomY} to the start values (or 1.0).
|
|
4932
|
+
* 'update' adapts these values accoring to the new bounding box and 'keep' does nothing.
|
|
4906
4933
|
* @returns {JXG.Board} Reference to the board
|
|
4907
4934
|
*/
|
|
4908
|
-
setBoundingBox: function (bbox, keepaspectratio) {
|
|
4909
|
-
var h, w,
|
|
4935
|
+
setBoundingBox: function (bbox, keepaspectratio, setZoom) {
|
|
4936
|
+
var h, w, ux, uy,
|
|
4937
|
+
offX = 0,
|
|
4938
|
+
offY = 0,
|
|
4910
4939
|
dim = Env.getDimensions(this.container, this.document);
|
|
4911
4940
|
|
|
4912
4941
|
if (!Type.isArray(bbox)) {
|
|
4913
4942
|
return this;
|
|
4914
4943
|
}
|
|
4944
|
+
|
|
4915
4945
|
if (bbox[0] < this.maxboundingbox[0] ||
|
|
4916
4946
|
bbox[1] > this.maxboundingbox[1] ||
|
|
4917
4947
|
bbox[2] > this.maxboundingbox[2] ||
|
|
@@ -4919,20 +4949,28 @@ define([
|
|
|
4919
4949
|
return this;
|
|
4920
4950
|
}
|
|
4921
4951
|
|
|
4922
|
-
|
|
4952
|
+
if (!Type.exists(setZoom)) {
|
|
4953
|
+
setZoom = 'reset';
|
|
4954
|
+
}
|
|
4955
|
+
|
|
4956
|
+
ux = this.unitX;
|
|
4957
|
+
uy = this.unitY;
|
|
4923
4958
|
|
|
4924
4959
|
this.canvasWidth = parseInt(dim.width, 10);
|
|
4925
4960
|
this.canvasHeight = parseInt(dim.height, 10);
|
|
4926
4961
|
w = this.canvasWidth;
|
|
4927
4962
|
h = this.canvasHeight;
|
|
4928
|
-
|
|
4929
4963
|
if (keepaspectratio) {
|
|
4930
4964
|
this.unitX = w / (bbox[2] - bbox[0]);
|
|
4931
4965
|
this.unitY = h / (bbox[1] - bbox[3]);
|
|
4932
4966
|
if (Math.abs(this.unitX) < Math.abs(this.unitY)) {
|
|
4933
4967
|
this.unitY = Math.abs(this.unitX) * this.unitY / Math.abs(this.unitY);
|
|
4968
|
+
// Add the additional units in equal portions above and below
|
|
4969
|
+
offY = (h / this.unitY - (bbox[1] - bbox[3])) * 0.5;
|
|
4934
4970
|
} else {
|
|
4935
4971
|
this.unitX = Math.abs(this.unitY) * this.unitX / Math.abs(this.unitX);
|
|
4972
|
+
// Add the additional units in equal portions left and right
|
|
4973
|
+
offX = (w / this.unitX - (bbox[2] - bbox[0])) * 0.5;
|
|
4936
4974
|
}
|
|
4937
4975
|
this.keepaspectratio = true;
|
|
4938
4976
|
} else {
|
|
@@ -4941,7 +4979,15 @@ define([
|
|
|
4941
4979
|
this.keepaspectratio = false;
|
|
4942
4980
|
}
|
|
4943
4981
|
|
|
4944
|
-
this.moveOrigin(-this.unitX * bbox[0], this.unitY * bbox[1]);
|
|
4982
|
+
this.moveOrigin(-this.unitX * (bbox[0] - offX), this.unitY * (bbox[1] + offY));
|
|
4983
|
+
|
|
4984
|
+
if (setZoom === 'update') {
|
|
4985
|
+
this.zoomX *= this.unitX / ux;
|
|
4986
|
+
this.zoomY *= this.unitY / uy;
|
|
4987
|
+
} else if (setZoom === 'reset') {
|
|
4988
|
+
this.zoomX = Type.exists(this.attr.zoomx) ? this.attr.zoomx : 1.0;
|
|
4989
|
+
this.zoomY = Type.exists(this.attr.zoomy) ? this.attr.zoomy : 1.0;
|
|
4990
|
+
}
|
|
4945
4991
|
|
|
4946
4992
|
return this;
|
|
4947
4993
|
},
|
|
@@ -5266,7 +5312,7 @@ define([
|
|
|
5266
5312
|
for (i = 0; i < l; i++) {
|
|
5267
5313
|
olist[flist[i].id] = flist[i];
|
|
5268
5314
|
}
|
|
5269
|
-
s = new
|
|
5315
|
+
s = new Composition(olist);
|
|
5270
5316
|
// it's an element which has been deleted (and still hangs around, e.g. in an attractor list
|
|
5271
5317
|
} else if (Type.isObject(s) && Type.exists(s.id) && !Type.exists(this.objects[s.id])) {
|
|
5272
5318
|
s = null;
|
|
@@ -5613,7 +5659,7 @@ define([
|
|
|
5613
5659
|
* @name JXG.Board#move
|
|
5614
5660
|
* @param {Event} e The browser's event object.
|
|
5615
5661
|
* @param {Number} mode The mode the board currently is in
|
|
5616
|
-
* @see
|
|
5662
|
+
* @see JXG.Board#mode
|
|
5617
5663
|
*/
|
|
5618
5664
|
__evt__move: function (e, mode) { },
|
|
5619
5665
|
|
|
@@ -5623,7 +5669,7 @@ define([
|
|
|
5623
5669
|
* @name JXG.Board#mousemove
|
|
5624
5670
|
* @param {Event} e The browser's event object.
|
|
5625
5671
|
* @param {Number} mode The mode the board currently is in
|
|
5626
|
-
* @see
|
|
5672
|
+
* @see JXG.Board#mode
|
|
5627
5673
|
*/
|
|
5628
5674
|
__evt__mousemove: function (e, mode) { },
|
|
5629
5675
|
|
|
@@ -5633,7 +5679,7 @@ define([
|
|
|
5633
5679
|
* @name JXG.Board#penmove
|
|
5634
5680
|
* @param {Event} e The browser's event object.
|
|
5635
5681
|
* @param {Number} mode The mode the board currently is in
|
|
5636
|
-
* @see
|
|
5682
|
+
* @see JXG.Board#mode
|
|
5637
5683
|
*/
|
|
5638
5684
|
__evt__penmove: function (e, mode) { },
|
|
5639
5685
|
|
|
@@ -5644,7 +5690,7 @@ define([
|
|
|
5644
5690
|
* @name JXG.Board#pointermove
|
|
5645
5691
|
* @param {Event} e The browser's event object.
|
|
5646
5692
|
* @param {Number} mode The mode the board currently is in
|
|
5647
|
-
* @see
|
|
5693
|
+
* @see JXG.Board#mode
|
|
5648
5694
|
*/
|
|
5649
5695
|
__evt__pointermove: function (e, mode) { },
|
|
5650
5696
|
|
|
@@ -5654,7 +5700,7 @@ define([
|
|
|
5654
5700
|
* @name JXG.Board#touchmove
|
|
5655
5701
|
* @param {Event} e The browser's event object.
|
|
5656
5702
|
* @param {Number} mode The mode the board currently is in
|
|
5657
|
-
* @see
|
|
5703
|
+
* @see JXG.Board#mode
|
|
5658
5704
|
*/
|
|
5659
5705
|
__evt__touchmove: function (e, mode) { },
|
|
5660
5706
|
|
|
@@ -5824,6 +5870,12 @@ define([
|
|
|
5824
5870
|
* <p>
|
|
5825
5871
|
* The wrapping div has the CSS class 'jxgbox_wrap_private' which is
|
|
5826
5872
|
* defined in the file 'jsxgraph.css'
|
|
5873
|
+
* <p>
|
|
5874
|
+
* This feature is not available on iPhones (as of December 2021).
|
|
5875
|
+
*
|
|
5876
|
+
* @param {String} id (Optional) id of the div element which is brought to fullscreen.
|
|
5877
|
+
* If not provided, this defaults to the JSXGraph div. However, it may be necessary for the aspect ratio trick
|
|
5878
|
+
* which using padding-bottom/top and an out div element. Then, the id of the outer div has to be supplied.
|
|
5827
5879
|
*
|
|
5828
5880
|
* @return {JXG.Board} Reference to the board
|
|
5829
5881
|
*
|
|
@@ -5845,29 +5897,76 @@ define([
|
|
|
5845
5897
|
* var p = board.create('point', [0, 1]);
|
|
5846
5898
|
* board_d5bab8b6 = board;
|
|
5847
5899
|
* })();
|
|
5848
|
-
* <button onClick="board_d5bab8b6.toFullscreen()">Fullscreen</button>
|
|
5849
|
-
*
|
|
5850
5900
|
* </script>
|
|
5901
|
+
* <button onClick="board_d5bab8b6.toFullscreen()">Fullscreen</button>
|
|
5851
5902
|
* <pre>
|
|
5852
5903
|
*
|
|
5904
|
+
* @example
|
|
5905
|
+
* <div id='outer' style='max-width: 500px; margin: 0 auto;'>
|
|
5906
|
+
* <div id='jxgbox' class='jxgbox' style='height: 0; padding-bottom: 100%'></div>
|
|
5907
|
+
* </div>
|
|
5908
|
+
* <button onClick="board.toFullscreen('outer')">Fullscreen</button>
|
|
5909
|
+
*
|
|
5910
|
+
* <script language="Javascript" type='text/javascript'>
|
|
5911
|
+
* var board = JXG.JSXGraph.initBoard('jxgbox', {
|
|
5912
|
+
* axis:true,
|
|
5913
|
+
* boundingbox:[-5,5,5,-5],
|
|
5914
|
+
* fullscreen: { id: 'outer' },
|
|
5915
|
+
* showFullscreen: true
|
|
5916
|
+
* });
|
|
5917
|
+
* var p = board.create('point', [-2, 3], {});
|
|
5918
|
+
* </script>
|
|
5919
|
+
*
|
|
5920
|
+
* </pre><div id="JXG7103f6b_outer" style='max-width: 500px; margin: 0 auto;'>
|
|
5921
|
+
* <div id="JXG7103f6be-6993-4ff8-8133-c78e50a8afac" class="jxgbox" style="height: 0; padding-bottom: 100%;"></div>
|
|
5922
|
+
* </div>
|
|
5923
|
+
* <button onClick="board_JXG7103f6be.toFullscreen('JXG7103f6b_outer')">Fullscreen</button>
|
|
5924
|
+
* <script type="text/javascript">
|
|
5925
|
+
* var board_JXG7103f6be;
|
|
5926
|
+
* (function() {
|
|
5927
|
+
* var board = JXG.JSXGraph.initBoard('JXG7103f6be-6993-4ff8-8133-c78e50a8afac',
|
|
5928
|
+
* {boundingbox: [-8, 8, 8,-8], axis: true, fullscreen: { id: 'JXG7103f6b_outer' }, showFullscreen: true,
|
|
5929
|
+
* showcopyright: false, shownavigation: false});
|
|
5930
|
+
* var p = board.create('point', [-2, 3], {});
|
|
5931
|
+
* board_JXG7103f6be = board;
|
|
5932
|
+
* })();
|
|
5933
|
+
*
|
|
5934
|
+
* </script><pre>
|
|
5935
|
+
*
|
|
5936
|
+
*
|
|
5853
5937
|
*/
|
|
5854
|
-
toFullscreen: function() {
|
|
5855
|
-
var
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5938
|
+
toFullscreen: function (id) {
|
|
5939
|
+
var wrap_id, wrap_node, inner_node;
|
|
5940
|
+
|
|
5941
|
+
id = id || this.container;
|
|
5942
|
+
this._fullscreen_inner_id = id;
|
|
5943
|
+
inner_node = document.getElementById(id);
|
|
5944
|
+
wrap_id = 'fullscreenwrap_' + id;
|
|
5859
5945
|
|
|
5860
|
-
//
|
|
5861
|
-
if (
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5946
|
+
// Wrap a div around the JSXGraph div.
|
|
5947
|
+
if (this.document.getElementById(wrap_id)) {
|
|
5948
|
+
wrap_node = this.document.getElementById(wrap_id);
|
|
5949
|
+
} else {
|
|
5950
|
+
wrap_node = document.createElement('div');
|
|
5951
|
+
wrap_node.classList.add('JXG_wrap_private');
|
|
5952
|
+
wrap_node.setAttribute('id', wrap_id);
|
|
5953
|
+
inner_node.parentNode.insertBefore(wrap_node, inner_node);
|
|
5954
|
+
wrap_node.appendChild(inner_node);
|
|
5867
5955
|
}
|
|
5868
5956
|
|
|
5869
|
-
//
|
|
5870
|
-
|
|
5957
|
+
// Get the real width and height of the JSXGraph div
|
|
5958
|
+
// and determine the scaling and vertical shift amount
|
|
5959
|
+
this._fullscreen_res = Env._getScaleFactors(inner_node);
|
|
5960
|
+
|
|
5961
|
+
// Trigger fullscreen mode
|
|
5962
|
+
wrap_node.requestFullscreen = wrap_node.requestFullscreen ||
|
|
5963
|
+
wrap_node.webkitRequestFullscreen ||
|
|
5964
|
+
wrap_node.mozRequestFullScreen ||
|
|
5965
|
+
wrap_node.msRequestFullscreen;
|
|
5966
|
+
|
|
5967
|
+
if (wrap_node.requestFullscreen) {
|
|
5968
|
+
wrap_node.requestFullscreen();
|
|
5969
|
+
}
|
|
5871
5970
|
|
|
5872
5971
|
return this;
|
|
5873
5972
|
},
|
|
@@ -5879,40 +5978,69 @@ define([
|
|
|
5879
5978
|
*
|
|
5880
5979
|
* @param {Object} evt fullscreen event object (unused)
|
|
5881
5980
|
*/
|
|
5882
|
-
fullscreenListener: function(evt) {
|
|
5883
|
-
var
|
|
5981
|
+
fullscreenListener: function (evt) {
|
|
5982
|
+
var res, inner_id, inner_node;
|
|
5884
5983
|
|
|
5984
|
+
inner_id = this._fullscreen_inner_id;
|
|
5985
|
+
if (!Type.exists(inner_id)) {
|
|
5986
|
+
return;
|
|
5987
|
+
}
|
|
5988
|
+
|
|
5989
|
+
document.fullscreenElement = document.fullscreenElement ||
|
|
5990
|
+
document.webkitFullscreenElement ||
|
|
5991
|
+
document.mozFullscreenElement ||
|
|
5992
|
+
document.msFullscreenElement;
|
|
5993
|
+
|
|
5994
|
+
inner_node = document.getElementById(inner_id);
|
|
5885
5995
|
// If full screen mode is started we have to remove CSS margin around the JSXGraph div.
|
|
5886
5996
|
// Otherwise, the positioning of the fullscreen div will be false.
|
|
5887
5997
|
// When leaving the fullscreen mode, the margin is put back in.
|
|
5888
|
-
|
|
5889
5998
|
if (document.fullscreenElement) {
|
|
5890
|
-
//
|
|
5999
|
+
// Just entered fullscreen mode
|
|
5891
6000
|
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
// Do the shifting and scaling via CSS pseudo rules
|
|
5895
|
-
// We do this after fullscreen mode has been established to get the correct size
|
|
5896
|
-
// of the JSXGraph div
|
|
5897
|
-
res = Env._getScaleFactors(el);
|
|
5898
|
-
Env.scaleJSXGraphDiv('#' + document.fullscreenElement.id, '#' + this.container, res.scale, res.vshift);
|
|
6001
|
+
// Get the data computed in board.toFullscreen()
|
|
6002
|
+
res = this._fullscreen_res;
|
|
5899
6003
|
|
|
5900
6004
|
// Store the scaling data.
|
|
5901
6005
|
// It is used in AbstractRenderer.updateText to restore the scaling matrix
|
|
5902
6006
|
// which is removed by MathJax.
|
|
5903
6007
|
// Further, the CSS margin has to be removed when in fullscreen mode,
|
|
5904
6008
|
// and must be restored later.
|
|
5905
|
-
|
|
6009
|
+
inner_node._cssFullscreenStore = {
|
|
6010
|
+
id: document.fullscreenElement.id,
|
|
5906
6011
|
isFullscreen: true,
|
|
5907
|
-
margin:
|
|
5908
|
-
|
|
6012
|
+
margin: inner_node.style.margin,
|
|
6013
|
+
width: inner_node.style.width,
|
|
6014
|
+
scale: res.scale,
|
|
5909
6015
|
vshift: res.vshift
|
|
5910
6016
|
};
|
|
5911
|
-
} else if (Type.exists(el._cssFullscreenStore)) {
|
|
5912
|
-
// Left fullscreen mode
|
|
5913
6017
|
|
|
5914
|
-
|
|
5915
|
-
|
|
6018
|
+
inner_node.style.margin = '';
|
|
6019
|
+
inner_node.style.width = res.width + 'px';
|
|
6020
|
+
|
|
6021
|
+
// Do the shifting and scaling via CSS pseudo rules
|
|
6022
|
+
// We do this after fullscreen mode has been established to get the correct size
|
|
6023
|
+
// of the JSXGraph div.
|
|
6024
|
+
Env.scaleJSXGraphDiv(document.fullscreenElement.id, inner_id, res.scale, res.vshift);
|
|
6025
|
+
|
|
6026
|
+
// Clear document.fullscreenElement, because Safari doesn't to it and
|
|
6027
|
+
// when leaving full screen mode it is still set.
|
|
6028
|
+
document.fullscreenElement = null;
|
|
6029
|
+
|
|
6030
|
+
} else if (Type.exists(inner_node._cssFullscreenStore)) {
|
|
6031
|
+
// Just left the fullscreen mode
|
|
6032
|
+
|
|
6033
|
+
// Remove the CSS rules added in Env.scaleJSXGraphDiv
|
|
6034
|
+
try {
|
|
6035
|
+
document.styleSheets[document.styleSheets.length - 1].deleteRule(0);
|
|
6036
|
+
} catch (err) {
|
|
6037
|
+
console.log('JSXGraph: Could not remove CSS rules for full screen mode');
|
|
6038
|
+
}
|
|
6039
|
+
|
|
6040
|
+
inner_node._cssFullscreenStore.isFullscreen = false;
|
|
6041
|
+
inner_node.style.margin = inner_node._cssFullscreenStore.margin;
|
|
6042
|
+
inner_node.style.width = inner_node._cssFullscreenStore.width;
|
|
6043
|
+
|
|
5916
6044
|
}
|
|
5917
6045
|
|
|
5918
6046
|
this.updateCSSTransforms();
|