jsxgraph 1.4.2 → 1.4.5

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/src/base/board.js CHANGED
@@ -816,8 +816,12 @@ define([
816
816
  */
817
817
  getCoordsTopLeftCorner: function () {
818
818
  var cPos, doc, crect,
819
- docElement = this.document.documentElement || this.document.body.parentNode,
820
- docBody = this.document.body,
819
+ // In ownerDoc we need the "real" document object.
820
+ // The first version is used in the case of shadowDom,
821
+ // the second case in the "normal" case.
822
+ ownerDoc = this.document.ownerDocument || this.document,
823
+ docElement = ownerDoc.documentElement || this.document.body.parentNode,
824
+ docBody = ownerDoc.body,
821
825
  container = this.containerObj,
822
826
  // viewport, content,
823
827
  zoom, o;
@@ -1192,7 +1196,8 @@ define([
1192
1196
  */
1193
1197
  twoFingerTouchObject: function (tar, drag, id) {
1194
1198
  var np, op, nd, od,
1195
- d, alpha,
1199
+ d,
1200
+ alpha = 0,
1196
1201
  S, t1, t3, t4, t5,
1197
1202
  ar, i, len,
1198
1203
  fixEl, moveEl, fix;
@@ -1226,7 +1231,9 @@ define([
1226
1231
  return;
1227
1232
  }
1228
1233
 
1229
- alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));
1234
+ if (Type.evaluate(drag.visProp.rotatable)) {
1235
+ alpha = Geometry.rad(op.slice(1), fix.slice(1), np.slice(1));
1236
+ }
1230
1237
 
1231
1238
  t1 = this.create('transform', [alpha, [fix[1], fix[2]]], {type: 'rotate'});
1232
1239
  t1.update();
@@ -2397,7 +2404,8 @@ define([
2397
2404
  * @returns {Boolean}
2398
2405
  */
2399
2406
  pointerUpListener: function (evt) {
2400
- var i, j, found, touchTargets;
2407
+ var i, j, found, touchTargets,
2408
+ updateNeeded = false;
2401
2409
 
2402
2410
  this.triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);
2403
2411
  this.displayInfobox(false);
@@ -2417,10 +2425,14 @@ define([
2417
2425
  }
2418
2426
  }
2419
2427
 
2428
+ this.originMoveEnd();
2429
+ this.update();
2430
+
2420
2431
  // selection
2421
2432
  if (this.selectingMode) {
2422
2433
  this._stopSelecting(evt);
2423
2434
  this.triggerEventHandlers(['touchstopselecting', 'pointerstopselecting', 'stopselecting'], [evt]);
2435
+ this.stopSelectionMode();
2424
2436
  } else {
2425
2437
  for (i = this.downObjects.length - 1; i > -1; i--) {
2426
2438
  found = false;
@@ -2431,32 +2443,38 @@ define([
2431
2443
  }
2432
2444
  if (!found) {
2433
2445
  this.downObjects[i].triggerEventHandlers(['touchend', 'up', 'pointerup', 'MSPointerUp'], [evt]);
2434
- this.downObjects[i].snapToGrid();
2435
- this.downObjects[i].snapToPoints();
2446
+ if (!Type.exists(this.downObjects[i].coords)) {
2447
+ // snapTo methods have to be called e.g. for line elements here.
2448
+ // For coordsElements there might be a conflict with
2449
+ // attractors, see commit from 2022.04.08, 11:12:18.
2450
+ this.downObjects[i].snapToGrid();
2451
+ this.downObjects[i].snapToPoints();
2452
+ updateNeeded = true;
2453
+ }
2436
2454
  this.downObjects.splice(i, 1);
2437
2455
  }
2438
2456
  }
2439
2457
  }
2440
2458
 
2441
- // this._pointerRemoveTouches(evt);
2442
- // if (this._board_touches.length === 0) {
2443
- if (this.hasPointerUp) {
2444
- if (window.navigator.msPointerEnabled) { // IE10-
2445
- Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);
2446
- } else {
2447
- Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this);
2448
- Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this);
2449
- }
2450
- this.hasPointerUp = false;
2459
+ if (this.hasPointerUp) {
2460
+ if (window.navigator.msPointerEnabled) { // IE10-
2461
+ Env.removeEvent(this.document, 'MSPointerUp', this.pointerUpListener, this);
2462
+ } else {
2463
+ Env.removeEvent(this.document, 'pointerup', this.pointerUpListener, this);
2464
+ Env.removeEvent(this.document, 'pointercancel', this.pointerUpListener, this);
2451
2465
  }
2466
+ this.hasPointerUp = false;
2467
+ }
2452
2468
 
2453
- // this.dehighlightAll();
2454
- // this.updateQuality = this.BOARD_QUALITY_HIGH;
2455
- // this.mode = this.BOARD_MODE_NONE;
2469
+ // this.dehighlightAll();
2470
+ // this.updateQuality = this.BOARD_QUALITY_HIGH;
2471
+ // this.mode = this.BOARD_MODE_NONE;
2456
2472
 
2457
- this.originMoveEnd();
2473
+ // this.originMoveEnd();
2474
+ if (updateNeeded) {
2458
2475
  this.update();
2459
- // }
2476
+ }
2477
+
2460
2478
  // After one finger leaves the screen the gesture is stopped.
2461
2479
  this._pointerClearTouches();
2462
2480
  return true;
@@ -2790,7 +2808,8 @@ define([
2790
2808
  eps = this.options.precision.touch,
2791
2809
  tmpTouches = [], found, foundNumber,
2792
2810
  evtTouches = evt && evt[JXG.touchProperty],
2793
- touchTargets;
2811
+ touchTargets,
2812
+ updateNeeded = false;
2794
2813
 
2795
2814
  this.triggerEventHandlers(['touchend', 'up'], [evt]);
2796
2815
  this.displayInfobox(false);
@@ -2799,6 +2818,7 @@ define([
2799
2818
  if (this.selectingMode) {
2800
2819
  this._stopSelecting(evt);
2801
2820
  this.triggerEventHandlers(['touchstopselecting', 'stopselecting'], [evt]);
2821
+ this.stopSelectionMode();
2802
2822
  } else if (evtTouches && evtTouches.length > 0) {
2803
2823
  for (i = 0; i < this.touches.length; i++) {
2804
2824
  tmpTouches[i] = this.touches[i];
@@ -2890,8 +2910,14 @@ define([
2890
2910
  }
2891
2911
  if (!found) {
2892
2912
  this.downObjects[i].triggerEventHandlers(['touchup', 'up'], [evt]);
2893
- this.downObjects[i].snapToGrid();
2894
- this.downObjects[i].snapToPoints();
2913
+ if (!Type.exists(this.downObjects[i].coords)) {
2914
+ // snapTo methods have to be called e.g. for line elements here.
2915
+ // For coordsElements there might be a conflict with
2916
+ // attractors, see commit from 2022.04.08, 11:12:18.
2917
+ this.downObjects[i].snapToGrid();
2918
+ this.downObjects[i].snapToPoints();
2919
+ updateNeeded = true;
2920
+ }
2895
2921
  this.downObjects.splice(i, 1);
2896
2922
  }
2897
2923
  }
@@ -2907,7 +2933,9 @@ define([
2907
2933
  this.updateQuality = this.BOARD_QUALITY_HIGH;
2908
2934
 
2909
2935
  this.originMoveEnd();
2910
- this.update();
2936
+ if (updateNeeded) {
2937
+ this.update();
2938
+ }
2911
2939
  }
2912
2940
 
2913
2941
  return true;
@@ -3055,9 +3083,14 @@ define([
3055
3083
  this.updateQuality = this.BOARD_QUALITY_HIGH;
3056
3084
 
3057
3085
  if (this.mouse && this.mouse.obj) {
3058
- // The parameter is needed for lines with snapToGrid enabled
3059
- this.mouse.obj.snapToGrid(this.mouse.targets[0]);
3060
- this.mouse.obj.snapToPoints();
3086
+ if (!Type.exists(this.mouse.obj.coords)) {
3087
+ // snapTo methods have to be called e.g. for line elements here.
3088
+ // For coordsElements there might be a conflict with
3089
+ // attractors, see commit from 2022.04.08, 11:12:18.
3090
+ // The parameter is needed for lines with snapToGrid enabled
3091
+ this.mouse.obj.snapToGrid(this.mouse.targets[0]);
3092
+ this.mouse.obj.snapToPoints();
3093
+ }
3061
3094
  }
3062
3095
 
3063
3096
  this.originMoveEnd();
@@ -3068,6 +3101,7 @@ define([
3068
3101
  if (this.selectingMode) {
3069
3102
  this._stopSelecting(evt);
3070
3103
  this.triggerEventHandlers(['mousestopselecting', 'stopselecting'], [evt]);
3104
+ this.stopSelectionMode();
3071
3105
  } else {
3072
3106
  for (i = 0; i < this.downObjects.length; i++) {
3073
3107
  this.downObjects[i].triggerEventHandlers(['mouseup', 'up'], [evt]);
@@ -3113,11 +3147,18 @@ define([
3113
3147
  },
3114
3148
 
3115
3149
  /**
3116
- * Allow moving of JSXGraph elements with arrow keys
3117
- * and zooming of the construction with + / -.
3150
+ * Allow moving of JSXGraph elements with arrow keys.
3151
+ * The selection of the element is done with the tab key. For this,
3152
+ * the attribute "tabindex" of the element has to be set to some number (default=0).
3153
+ * tabindex corresponds to the HTML attribute of the same name.
3154
+ * <p>
3118
3155
  * Panning of the construction is done with arrow keys
3119
- * if the pan key (shift or ctrl) is pressed.
3120
- * The selection of the element is done with the tab key.
3156
+ * if the pan key (shift or ctrl - depending on the board attributes) is pressed.
3157
+ * <p>
3158
+ * Zooming is triggered with the keys +, o, -, if
3159
+ * the pan key (shift or ctrl - depending on the board attributes) is pressed.
3160
+ * <p>
3161
+ * Keyboard control (move, pan, and zoom) is disabled if an HTML element of type input or textarea has received focus.
3121
3162
  *
3122
3163
  * @param {Event} evt The browser's event object
3123
3164
  *
@@ -3128,7 +3169,7 @@ define([
3128
3169
  */
3129
3170
  keyDownListener: function (evt) {
3130
3171
  var id_node = evt.target.id,
3131
- id, el, res,
3172
+ id, el, res, doc,
3132
3173
  sX = 0,
3133
3174
  sY = 0,
3134
3175
  // dx, dy are provided in screen units and
@@ -3143,6 +3184,15 @@ define([
3143
3184
  return false;
3144
3185
  }
3145
3186
 
3187
+ // An element of type input or textarea has foxus, get out of here.
3188
+ doc = this.containerObj.shadowRoot || document;
3189
+ if (doc.activeElement) {
3190
+ el = doc.activeElement;
3191
+ if (el.tagName === 'INPUT' || el.tagName === 'textarea') {
3192
+ return false;
3193
+ }
3194
+ }
3195
+
3146
3196
  // Get the JSXGraph id from the id of the SVG node.
3147
3197
  id = id_node.replace(this.containerObj.id + '_', '');
3148
3198
  el = this.select(id);
@@ -3151,12 +3201,15 @@ define([
3151
3201
  actPos = el.coords.usrCoords.slice(1);
3152
3202
  }
3153
3203
 
3154
- if (Type.evaluate(this.attr.keyboard.panshift) || Type.evaluate(this.attr.keyboard.panctrl)) {
3155
- doZoom = true;
3156
- }
3157
-
3158
3204
  if ((Type.evaluate(this.attr.keyboard.panshift) && evt.shiftKey) ||
3159
3205
  (Type.evaluate(this.attr.keyboard.panctrl) && evt.ctrlKey)) {
3206
+ // Pan key has been pressed
3207
+
3208
+ if (Type.evaluate(this.attr.zoom.enabled) === true) {
3209
+ doZoom = true;
3210
+ }
3211
+
3212
+ // Arrow keys
3160
3213
  if (evt.keyCode === 38) { // up
3161
3214
  this.clickUpArrow();
3162
3215
  } else if (evt.keyCode === 40) { // down
@@ -3165,10 +3218,20 @@ define([
3165
3218
  this.clickLeftArrow();
3166
3219
  } else if (evt.keyCode === 39) { // right
3167
3220
  this.clickRightArrow();
3221
+
3222
+ // Zoom keys
3223
+ } else if (doZoom && evt.keyCode === 171) { // +
3224
+ this.zoomIn();
3225
+ } else if (doZoom && evt.keyCode === 173) { // -
3226
+ this.zoomOut();
3227
+ } else if (doZoom && evt.keyCode === 79) { // o
3228
+ this.zoom100();
3229
+
3168
3230
  } else {
3169
3231
  done = false;
3170
3232
  }
3171
3233
  } else {
3234
+
3172
3235
  // Adapt dx, dy to snapToGrid and attractToGrid
3173
3236
  // snapToGrid has priority.
3174
3237
  if (Type.exists(el.visProp)) {
@@ -3211,14 +3274,6 @@ define([
3211
3274
  dir = [-dx, 0];
3212
3275
  } else if (evt.keyCode === 39) { // right
3213
3276
  dir = [dx, 0];
3214
- // } else if (evt.keyCode === 9) { // tab
3215
-
3216
- } else if (doZoom && evt.key === '+') { // +
3217
- this.zoomIn();
3218
- } else if (doZoom && evt.key === '-') { // -
3219
- this.zoomOut();
3220
- } else if (doZoom && evt.key === 'o') { // o
3221
- this.zoom100();
3222
3277
  } else {
3223
3278
  done = false;
3224
3279
  }
@@ -3248,15 +3303,16 @@ define([
3248
3303
 
3249
3304
  this.update();
3250
3305
 
3251
- if (done) {
3306
+ if (done && Type.exists(evt.preventDefault)) {
3252
3307
  evt.preventDefault();
3253
3308
  }
3254
- return true;
3309
+ return done;
3255
3310
  },
3256
3311
 
3257
3312
  /**
3258
3313
  * Event listener for SVG elements getting focus.
3259
3314
  * This is needed for highlighting when using keyboard control.
3315
+ * Only elements having the attribute "tabindex" can receive focus.
3260
3316
  *
3261
3317
  * @see JXG.Board#keyFocusOutListener
3262
3318
  * @see JXG.Board#keyDownListener
@@ -3286,6 +3342,7 @@ define([
3286
3342
  /**
3287
3343
  * Event listener for SVG elements losing focus.
3288
3344
  * This is needed for dehighlighting when using keyboard control.
3345
+ * Only elements having the attribute "tabindex" can receive focus.
3289
3346
  *
3290
3347
  * @see JXG.Board#keyFocusInListener
3291
3348
  * @see JXG.Board#keyDownListener
@@ -3336,8 +3393,8 @@ define([
3336
3393
  }
3337
3394
 
3338
3395
  // If div is invisible - do nothing
3339
- if (w <= 0 || h <= 0) {
3340
- return;
3396
+ if (w <= 0 || h <= 0 || isNaN(w) || isNaN(h)) {
3397
+ return;
3341
3398
  }
3342
3399
 
3343
3400
  // If bounding box is not yet initialized, do it now.
@@ -4742,12 +4799,12 @@ define([
4742
4799
  this.inUpdate = true;
4743
4800
 
4744
4801
  if (this.attr.minimizereflow === 'all' && this.containerObj && this.renderer.type !== 'vml') {
4745
- storeActiveEl = document.activeElement; // Store focus element
4802
+ storeActiveEl = this.document.activeElement; // Store focus element
4746
4803
  insert = this.renderer.removeToInsertLater(this.containerObj);
4747
4804
  }
4748
4805
 
4749
4806
  if (this.attr.minimizereflow === 'svg' && this.renderer.type === 'svg') {
4750
- storeActiveEl = document.activeElement;
4807
+ storeActiveEl = this.document.activeElement;
4751
4808
  insert = this.renderer.removeToInsertLater(this.renderer.svgRoot);
4752
4809
  }
4753
4810
 
@@ -5351,31 +5408,43 @@ define([
5351
5408
  */
5352
5409
  updateCSSTransforms: function () {
5353
5410
  var obj = this.containerObj,
5354
- o = obj,
5355
- o2 = obj;
5411
+ o = obj;
5412
+ // o2 = obj;
5356
5413
 
5357
5414
  this.cssTransMat = Env.getCSSTransformMatrix(o);
5358
5415
 
5416
+ // Newer variant of walking up the tree.
5417
+ // We walk up all parent nodes and collect possible CSS transforms.
5418
+ // Works also for ShadowDOM
5419
+ o = o.parentNode === o.getRootNode() ? o.parentNode.host : o.parentNode;
5420
+ while (o) {
5421
+ this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
5422
+ o = o.parentNode === o.getRootNode() ? o.parentNode.host : o.parentNode;
5423
+ }
5424
+ this.cssTransMat = Mat.inverse(this.cssTransMat);
5425
+
5359
5426
  /*
5360
5427
  * In Mozilla and Webkit: offsetParent seems to jump at least to the next iframe,
5361
5428
  * if not to the body. In IE and if we are in an position:absolute environment
5362
5429
  * offsetParent walks up the DOM hierarchy.
5363
5430
  * In order to walk up the DOM hierarchy also in Mozilla and Webkit
5364
5431
  * we need the parentNode steps.
5432
+ *
5433
+ * Seems to be outdated
5365
5434
  */
5366
- o = o.offsetParent;
5367
- while (o) {
5368
- this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
5435
+ // o = o.offsetParent;
5436
+ // while (o) {
5437
+ // this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
5369
5438
 
5370
- o2 = o2.parentNode;
5371
- while (o2 !== o) {
5372
- this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
5373
- o2 = o2.parentNode;
5374
- }
5439
+ // o2 = o2.parentNode;
5440
+ // while (o2 !== o) {
5441
+ // this.cssTransMat = Mat.matMatMult(Env.getCSSTransformMatrix(o), this.cssTransMat);
5442
+ // o2 = o2.parentNode;
5443
+ // }
5375
5444
 
5376
- o = o.offsetParent;
5377
- }
5378
- this.cssTransMat = Mat.inverse(this.cssTransMat);
5445
+ // o = o.offsetParent;
5446
+ // }
5447
+ // this.cssTransMat = Mat.inverse(this.cssTransMat);
5379
5448
 
5380
5449
  return this;
5381
5450
  },
@@ -5936,16 +6005,17 @@ define([
5936
6005
  *
5937
6006
  */
5938
6007
  toFullscreen: function (id) {
5939
- var wrap_id, wrap_node, inner_node;
6008
+ var wrap_id, wrap_node, inner_node,
6009
+ doc = this.document;
5940
6010
 
5941
6011
  id = id || this.container;
5942
6012
  this._fullscreen_inner_id = id;
5943
- inner_node = document.getElementById(id);
6013
+ inner_node = doc.getElementById(id);
5944
6014
  wrap_id = 'fullscreenwrap_' + id;
5945
6015
 
5946
6016
  // Wrap a div around the JSXGraph div.
5947
- if (this.document.getElementById(wrap_id)) {
5948
- wrap_node = this.document.getElementById(wrap_id);
6017
+ if (doc.getElementById(wrap_id)) {
6018
+ wrap_node = doc.getElementById(wrap_id);
5949
6019
  } else {
5950
6020
  wrap_node = document.createElement('div');
5951
6021
  wrap_node.classList.add('JXG_wrap_private');
@@ -5964,8 +6034,14 @@ define([
5964
6034
  wrap_node.mozRequestFullScreen ||
5965
6035
  wrap_node.msRequestFullscreen;
5966
6036
 
5967
- if (wrap_node.requestFullscreen) {
5968
- wrap_node.requestFullscreen();
6037
+ if (doc.fullscreenElement === null) {
6038
+ // Start fullscreen mode
6039
+ if (wrap_node.requestFullscreen) {
6040
+ wrap_node.requestFullscreen();
6041
+ }
6042
+ } else {
6043
+ // Leave fullscreen mode (e.g. when clicking on the icon)
6044
+ document.exitFullscreen();
5969
6045
  }
5970
6046
 
5971
6047
  return this;
@@ -5979,23 +6055,24 @@ define([
5979
6055
  * @param {Object} evt fullscreen event object (unused)
5980
6056
  */
5981
6057
  fullscreenListener: function (evt) {
5982
- var res, inner_id, inner_node;
6058
+ var res, inner_id, inner_node,
6059
+ doc = this.document;
5983
6060
 
5984
6061
  inner_id = this._fullscreen_inner_id;
5985
6062
  if (!Type.exists(inner_id)) {
5986
6063
  return;
5987
6064
  }
5988
6065
 
5989
- document.fullscreenElement = document.fullscreenElement ||
5990
- document.webkitFullscreenElement ||
5991
- document.mozFullscreenElement ||
5992
- document.msFullscreenElement;
6066
+ doc.fullscreenElement = doc.fullscreenElement ||
6067
+ doc.webkitFullscreenElement ||
6068
+ doc.mozFullscreenElement ||
6069
+ doc.msFullscreenElement;
5993
6070
 
5994
- inner_node = document.getElementById(inner_id);
6071
+ inner_node = doc.getElementById(inner_id);
5995
6072
  // If full screen mode is started we have to remove CSS margin around the JSXGraph div.
5996
6073
  // Otherwise, the positioning of the fullscreen div will be false.
5997
6074
  // When leaving the fullscreen mode, the margin is put back in.
5998
- if (document.fullscreenElement) {
6075
+ if (doc.fullscreenElement) {
5999
6076
  // Just entered fullscreen mode
6000
6077
 
6001
6078
  // Get the data computed in board.toFullscreen()
@@ -6007,7 +6084,7 @@ define([
6007
6084
  // Further, the CSS margin has to be removed when in fullscreen mode,
6008
6085
  // and must be restored later.
6009
6086
  inner_node._cssFullscreenStore = {
6010
- id: document.fullscreenElement.id,
6087
+ id: doc.fullscreenElement.id,
6011
6088
  isFullscreen: true,
6012
6089
  margin: inner_node.style.margin,
6013
6090
  width: inner_node.style.width,
@@ -6021,18 +6098,18 @@ define([
6021
6098
  // Do the shifting and scaling via CSS pseudo rules
6022
6099
  // We do this after fullscreen mode has been established to get the correct size
6023
6100
  // of the JSXGraph div.
6024
- Env.scaleJSXGraphDiv(document.fullscreenElement.id, inner_id, res.scale, res.vshift);
6101
+ Env.scaleJSXGraphDiv(doc.fullscreenElement.id, inner_id, res.scale, res.vshift, doc);
6025
6102
 
6026
- // Clear document.fullscreenElement, because Safari doesn't to it and
6103
+ // Clear this.document.fullscreenElement, because Safari doesn't to it and
6027
6104
  // when leaving full screen mode it is still set.
6028
- document.fullscreenElement = null;
6105
+ doc.fullscreenElement = null;
6029
6106
 
6030
6107
  } else if (Type.exists(inner_node._cssFullscreenStore)) {
6031
6108
  // Just left the fullscreen mode
6032
6109
 
6033
6110
  // Remove the CSS rules added in Env.scaleJSXGraphDiv
6034
6111
  try {
6035
- document.styleSheets[document.styleSheets.length - 1].deleteRule(0);
6112
+ doc.styleSheets[doc.styleSheets.length - 1].deleteRule(0);
6036
6113
  } catch (err) {
6037
6114
  console.log('JSXGraph: Could not remove CSS rules for full screen mode');
6038
6115
  }
@@ -6040,7 +6117,6 @@ define([
6040
6117
  inner_node._cssFullscreenStore.isFullscreen = false;
6041
6118
  inner_node.style.margin = inner_node._cssFullscreenStore.margin;
6042
6119
  inner_node.style.width = inner_node._cssFullscreenStore.width;
6043
-
6044
6120
  }
6045
6121
 
6046
6122
  this.updateCSSTransforms();
@@ -42,7 +42,7 @@ define(['jxg'], function (JXG) {
42
42
 
43
43
  var major = 1,
44
44
  minor = 4,
45
- patch = 2,
45
+ patch = 5,
46
46
  add = '', //'dev'
47
47
  version = major + '.' + minor + '.' + patch + (add ? '-' + add : ''),
48
48
  constants;
@@ -198,8 +198,6 @@ define([
198
198
  * @private
199
199
  */
200
200
  updateCoords: function (fromParent) {
201
- var i;
202
-
203
201
  if (!this.needsUpdate) {
204
202
  return this;
205
203
  }
@@ -326,7 +324,6 @@ define([
326
324
  doRound = true;
327
325
  newPos = 0.0;
328
326
  } else {
329
- //this.coords.setCoordinates(Const.COORDS_BY_USER, Geometry.projectPointToLine(this, slide, this.board).usrCoords, false);
330
327
  newCoords = Geometry.projectPointToLine(this, slide, this.board);
331
328
  p1c = p1c.usrCoords.slice(0);
332
329
  p2c = p2c.usrCoords.slice(0);
@@ -1833,7 +1830,7 @@ define([
1833
1830
  if (direction < 0) {
1834
1831
  alpha *= this.intervalCount / stepCount;
1835
1832
  } else {
1836
- alpha *= (stepCount - this.intervalCount);
1833
+ alpha *= (stepCount - this.intervalCount) / stepCount;
1837
1834
  }
1838
1835
  radius = this.slideObject.Radius();
1839
1836
 
@@ -1052,26 +1052,35 @@ define([
1052
1052
  },
1053
1053
 
1054
1054
  /**
1055
- * Resolves property shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>.
1056
- * Writes the expanded properties back to the given <tt>properties</tt>.
1057
- * @param {Object} properties
1058
- * @returns {Object} The given parameter with shortcuts expanded.
1055
+ * Resolves attribute shortcuts like <tt>color</tt> and expands them, e.g. <tt>strokeColor</tt> and <tt>fillColor</tt>.
1056
+ * Writes the expanded attributes back to the given <tt>attributes</tt>.
1057
+ * @param {Object} attributes object
1058
+ * @returns {Object} The given attributes object with shortcuts expanded.
1059
+ * @private
1059
1060
  */
1060
- resolveShortcuts: function (properties) {
1061
- var key, i;
1061
+ resolveShortcuts: function (attributes) {
1062
+ var key, i,
1063
+ j,
1064
+ subattr = ['traceattributes', 'traceAttributes'];
1062
1065
 
1063
1066
  for (key in Options.shortcuts) {
1064
1067
  if (Options.shortcuts.hasOwnProperty(key)) {
1065
- if (Type.exists(properties[key])) {
1066
- for (i = 0; i < Options.shortcuts[key].length; i++) {
1067
- if (!Type.exists(properties[Options.shortcuts[key][i]])) {
1068
- properties[Options.shortcuts[key][i]] = properties[key];
1068
+
1069
+ if (Type.exists(attributes[key])) {
1070
+ for (i = 0; i < Options.shortcuts[key].length; i++) {
1071
+ if (!Type.exists(attributes[Options.shortcuts[key][i]])) {
1072
+ attributes[Options.shortcuts[key][i]] = attributes[key];
1073
+ }
1074
+ }
1075
+ }
1076
+ for (j = 0; j < subattr.length; j++) {
1077
+ if (Type.isObject(attributes[subattr[j]])) {
1078
+ attributes[subattr[j]] = this.resolveShortcuts(attributes[subattr[j]]);
1079
+ }
1069
1080
  }
1070
1081
  }
1071
- }
1072
- }
1073
1082
  }
1074
- return properties;
1083
+ return attributes;
1075
1084
  },
1076
1085
 
1077
1086
  /**
@@ -324,7 +324,13 @@
324
324
  * an SVG foreignObject container.
325
325
  * <p>
326
326
  * Instead of board.create('foreignobject') the shortcut board.create('fo') may be used.
327
- *
327
+ *
328
+ * <p style="background-color:#dddddd; padding:10px"><b>NOTE:</b> In Safari up to version 15, a foreignObject does not obey the layer structure
329
+ * if it contains &lt;video&gt; or &lt;iframe&gt; tags, as well as elements which are
330
+ * positioned with <tt>position:absolute|relative|fixed</tt>. In this case, the foreignobject will be
331
+ * "above" the JSXGraph construction.
332
+ * </p>
333
+ *
328
334
  * @pseudo
329
335
  * @description
330
336
  * @name ForeignObject
package/src/base/line.js CHANGED
@@ -695,7 +695,7 @@ define([
695
695
  if (this.parents.length < 3) { // Line through two points
696
696
  this.point1.handleSnapToGrid(true, true);
697
697
  this.point2.handleSnapToGrid(true, true);
698
- } else if (Type.exists(pos)) { // Free line
698
+ } else if (Type.exists(pos)) { // Free line
699
699
  sX = Type.evaluate(this.visProp.snapsizex);
700
700
  sY = Type.evaluate(this.visProp.snapsizey);
701
701