jsxgraph 1.14.0 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/CHANGELOG.md +33 -3
  2. package/distrib/docs/3d_linspace3d.js.html +16 -10
  3. package/distrib/docs/3d_point3d.js.html +0 -5
  4. package/distrib/docs/3d_sphere3d.js.html +92 -69
  5. package/distrib/docs/3d_view3d.js.html +24 -16
  6. package/distrib/docs/Angle.html +7 -7
  7. package/distrib/docs/CircumcircleSector.html +2 -2
  8. package/distrib/docs/Conic.html +1 -1
  9. package/distrib/docs/Ellipse.html +23 -1
  10. package/distrib/docs/Hyperbola.html +24 -1
  11. package/distrib/docs/JXG.Board.infobox.html +1 -1
  12. package/distrib/docs/JXG.Board_.html +130 -130
  13. package/distrib/docs/JXG.CanvasRenderer.html +10 -10
  14. package/distrib/docs/JXG.Composition.html +3 -3
  15. package/distrib/docs/JXG.GeometryElement.html +26 -26
  16. package/distrib/docs/JXG.Math.Numerics.html +45 -47
  17. package/distrib/docs/JXG.Math.Statistics.html +14 -15
  18. package/distrib/docs/JXG.Math.Tiling.html +3 -7
  19. package/distrib/docs/JXG.Math.html +101 -83
  20. package/distrib/docs/JXG.Point3D.html +2 -2
  21. package/distrib/docs/JXG.SVGRenderer.html +12 -12
  22. package/distrib/docs/JXG.Sphere3D.html +1255 -2
  23. package/distrib/docs/JXG.View3D.html +29 -29
  24. package/distrib/docs/JXG.html +20 -20
  25. package/distrib/docs/MajorSector.html +1 -1
  26. package/distrib/docs/MinorSector.html +1 -1
  27. package/distrib/docs/NonReflexAngle.html +1 -1
  28. package/distrib/docs/Parabola.html +1 -1
  29. package/distrib/docs/Point3D.html +1 -1
  30. package/distrib/docs/ReflexAngle.html +1 -1
  31. package/distrib/docs/Sector.html +12 -12
  32. package/distrib/docs/Sphere3D.html +17 -1
  33. package/distrib/docs/View3D.html +1 -1
  34. package/distrib/docs/base_board.js.html +63 -13
  35. package/distrib/docs/base_composition.js.html +3 -3
  36. package/distrib/docs/base_constants.js.html +1 -1
  37. package/distrib/docs/base_element.js.html +2 -1
  38. package/distrib/docs/base_text.js.html +2 -2
  39. package/distrib/docs/element_conic.js.html +35 -1
  40. package/distrib/docs/element_sector.js.html +6 -3
  41. package/distrib/docs/index.html +1 -1
  42. package/distrib/docs/math_math.js.html +64 -35
  43. package/distrib/docs/math_numerics.js.html +13 -12
  44. package/distrib/docs/math_statistics.js.html +19 -19
  45. package/distrib/docs/math_tiling.js.html +6 -288
  46. package/distrib/docs/parser_jessiecode.js.html +1 -1
  47. package/distrib/docs/renderer_canvas.js.html +7 -6
  48. package/distrib/docs/renderer_svg.js.html +15 -7
  49. package/distrib/docs/scripts/jsxgraphcore.js +2 -2
  50. package/distrib/docs/styles/jsxgraph.css +1 -1
  51. package/distrib/docs/utils_type.js.html +11 -4
  52. package/distrib/geogebra.min.js +1 -1
  53. package/distrib/geonext.min.js +1 -1
  54. package/distrib/index.d.ts +11 -0
  55. package/distrib/intergeo.min.js +1 -1
  56. package/distrib/jsxgraph.css +1 -1
  57. package/distrib/jsxgraphcore.js +2 -2
  58. package/distrib/jsxgraphcore.mjs +2 -2
  59. package/distrib/jsxgraphcore.mjs.map +1 -1
  60. package/distrib/jsxgraphsrc.js +380 -496
  61. package/distrib/jsxgraphsrc.mjs +380 -496
  62. package/distrib/jsxgraphsrc.mjs.map +1 -1
  63. package/package.json +10 -12
  64. package/src/3d/linspace3d.js +16 -10
  65. package/src/3d/point3d.js +0 -5
  66. package/src/3d/sphere3d.js +92 -69
  67. package/src/3d/view3d.js +24 -16
  68. package/src/base/board.js +63 -13
  69. package/src/base/composition.js +3 -3
  70. package/src/base/constants.js +1 -1
  71. package/src/base/element.js +2 -1
  72. package/src/base/text.js +2 -2
  73. package/src/element/conic.js +35 -1
  74. package/src/element/sector.js +6 -3
  75. package/src/index.d.ts +11 -0
  76. package/src/math/math.js +64 -35
  77. package/src/math/numerics.js +13 -12
  78. package/src/math/statistics.js +19 -19
  79. package/src/math/tiling.js +6 -288
  80. package/src/parser/jessiecode.js +1 -1
  81. package/src/renderer/canvas.js +7 -6
  82. package/src/renderer/svg.js +15 -7
  83. package/src/utils/type.js +11 -4
  84. package/src/unused/bst.js +0 -475
  85. package/src/unused/heap.js +0 -135
  86. package/src/unused/locus.js +0 -162
  87. package/src/unused/server/JXG.py +0 -74
  88. package/src/unused/server/JXGServer.py +0 -94
  89. package/src/unused/server/JXGServerModule.py +0 -9
  90. package/src/unused/server/README.md +0 -63
  91. package/src/unused/server/RStats.py +0 -45
  92. package/src/unused/server/YahooFinance.py +0 -81
  93. package/src/unused/server/fft.py +0 -136
  94. package/src/unused/server/geoloci.py +0 -210
  95. package/src/unused/server/jxggroebner.py +0 -219
  96. package/src/unused/server/jxgtestplugin.py +0 -19
  97. package/src/unused/server/server.js +0 -280
  98. package/src/unused/sketch.js +0 -2895
  99. package/src/unused/symbolic.js +0 -416
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "jsxgraph",
3
3
  "description": "Interactive geometry, plotting, visualization",
4
4
  "homepage": "https://jsxgraph.org",
5
- "version": "1.14.0",
5
+ "version": "1.14.1",
6
6
  "exports": {
7
7
  "types": "./src/index.d.ts",
8
8
  "default": "./src/index.js"
@@ -65,20 +65,20 @@
65
65
  "eslint-plugin-prettier": "^5.5",
66
66
  "globals": "^15.4.0",
67
67
  "http-server": "^14.1.1",
68
- "jasmine-core": "^3.10.1",
68
+ "jasmine-core": ">=7.0.2",
69
69
  "jsdoc": "^4.0.5",
70
70
  "jshint": "^0.5.9",
71
71
  "jslint": "^0.12.1",
72
- "karma": "^6.4.3",
73
- "karma-chrome-launcher": "^3.2.0",
74
- "karma-detect-browsers": "^2.3.3",
75
- "karma-jasmine": "^5.1.0",
72
+ "karma": ">=6.4.4",
73
+ "karma-chrome-launcher": ">=3.2.0",
74
+ "karma-detect-browsers": ">=2.3.3",
75
+ "karma-jasmine": ">=5.1.0",
76
76
  "npmignore": "^0.3.1",
77
- "path-browserify": "^1.0.1",
78
- "prettier": "^3.8.1",
77
+ "path-browserify": ">=1.0.1",
78
+ "prettier": ">=3.8.1",
79
79
  "terser-webpack-plugin": ">=5.6.1",
80
- "webpack": ">=5.105.4",
81
- "webpack-cli": ">=7.2.1"
80
+ "webpack": ">=5.111.1",
81
+ "webpack-cli": ">=7.2.3"
82
82
  },
83
83
  "engines": {
84
84
  "node": ">=20.19.0"
@@ -92,8 +92,6 @@
92
92
  "serve": "http-server -c-1",
93
93
  "test": "make test"
94
94
  },
95
- "dependencies": {
96
- },
97
95
  "allowScripts": {
98
96
  "esbuild@0.28.2": true
99
97
  }
@@ -669,8 +669,8 @@ JXG.createLine3D = function (board, parents, attributes) {
669
669
  * @private
670
670
  */
671
671
  el.endpoints = endpoints;
672
- el.addChild(endpoints[0]);
673
- el.addChild(endpoints[1]);
672
+ // el.addChild(endpoints[0]); // Is done below
673
+ // el.addChild(endpoints[1]);
674
674
  // el.setParents(endpoints);
675
675
  el.addParents([point1, point2]);
676
676
 
@@ -2017,18 +2017,24 @@ JXG.createIntersectionLine3D = function (board, parents, attributes) {
2017
2017
  var view = parents[0],
2018
2018
  el1 = parents[1],
2019
2019
  el2 = parents[2],
2020
- ixnLine, i,// func,
2020
+ ixnLine, i,// f,
2021
2021
  attr = Type.copyAttributes(attributes, board.options, 'intersectionline3d'),
2022
2022
  pts = [];
2023
2023
 
2024
- // func = Geometry.intersectionFunction3D(view, el1, el2);
2024
+ // var func = Geometry.intersectionFunction3D(view, el1, el2);
2025
2025
  for (i = 0; i < 2; i++) {
2026
- pts[i] = view.create('point3d', [
2027
- // Use closures
2028
- (function(ii) {
2029
- return function() { return Geometry.intersectionFunction3D(view, el1, el2)[ii]; };
2030
- })(i)
2031
- ], attr['point' + (i + 1)]);
2026
+ try {
2027
+ pts[i] = view.create('point3d', [
2028
+ // Use closures
2029
+ (function (ii) {
2030
+ return function () { return Geometry.intersectionFunction3D(view, el1, el2)[ii]; };
2031
+ })(i)
2032
+ ], attr['point' + (i + 1)]);
2033
+ } catch (err) {
2034
+ throw new Error(
2035
+ "JSXGraph: Can't create IntersectionLine3D from the intersection of these types. Please check the intersecting elements."
2036
+ );
2037
+ }
2032
2038
  }
2033
2039
  ixnLine = view.create('line3d', pts, attr);
2034
2040
 
package/src/3d/point3d.js CHANGED
@@ -478,8 +478,6 @@ JXG.extend(
478
478
  }
479
479
  },
480
480
 
481
-
482
-
483
481
  /**
484
482
  * Starts an animated point movement towards the given coordinates `where`.
485
483
  * The animation is done after `time` milliseconds.
@@ -701,9 +699,6 @@ JXG.extend(
701
699
  });
702
700
  },
703
701
 
704
-
705
-
706
-
707
702
  // Not yet working
708
703
  __evt__update3D: function (oc) { }
709
704
  }
@@ -152,28 +152,52 @@ JXG.extend(
152
152
  JXG.Sphere3D.prototype,
153
153
  /** @lends JXG.Sphere3D.prototype */ {
154
154
 
155
+ /**
156
+ * Returns the x-coordinate of the sphere given as parametric surface for parameters `u` and `v`.
157
+ * @param {Number} u
158
+ * @param {Number} v
159
+ * @returns {Number} x-coordinate
160
+ */
155
161
  X: function(u, v) {
156
162
  var r = this.Radius();
157
163
  return r * Math.sin(u) * Math.cos(v);
158
164
  },
159
165
 
166
+ /**
167
+ * Returns the y-coordinate of the sphere given as parametric surface for parameters `u` and `v`.
168
+ * @param {Number} u
169
+ * @param {Number} v
170
+ * @returns {Number} y-coordinate
171
+ */
160
172
  Y: function(u, v) {
161
173
  var r = this.Radius();
162
174
  return r * Math.sin(u) * Math.sin(v);
163
175
  },
164
176
 
177
+ /**
178
+ * Returns the z-coordinate of the sphere given as parametric surface for parameters `u` and `v`.
179
+ * @param {Number} u
180
+ * @param {Number} v
181
+ * @returns {Number} z-coordinate
182
+ */
165
183
  Z: function(u, v) {
166
184
  var r = this.Radius();
167
185
  return r * Math.cos(u);
168
186
  },
169
187
 
188
+ /**
189
+ * The parameter range of `u`
190
+ * @type {Array}
191
+ */
170
192
  range_u: [0, 2 * Math.PI],
193
+
194
+ /**
195
+ * The parameter range of `v`
196
+ * @type {Array}
197
+ */
171
198
  range_v: [0, Math.PI],
172
199
 
173
200
  update: function () {
174
- if (this.projectionType !== this.view.projectionType) {
175
- this.rebuildProjection();
176
- }
177
201
  return this;
178
202
  },
179
203
 
@@ -221,34 +245,55 @@ JXG.extend(
221
245
  return NaN;
222
246
  },
223
247
 
224
- // The central projection of a sphere is an ellipse. The front and back
225
- // points of the sphere---that is, the points closest to and furthest
226
- // from the screen---project to the foci of the ellipse.
227
- //
228
- // To see this, look at the cone tangent to the sphere whose tip is at
229
- // the camera. The image of the sphere is the ellipse where this cone
230
- // intersects the screen. By acting on the sphere with scalings centered
231
- // on the camera, you can send it to either of the Dandelin spheres that
232
- // touch the screen at the foci of the image ellipse.
233
- //
234
- // This factory method produces two functions, `focusFn(-1)` and
235
- // `focusFn(1)`, that evaluate to the projections of the front and back
236
- // points of the sphere, respectively.
248
+ /**
249
+ * The central projection of a sphere is an ellipse. The front and back
250
+ * points of the sphere -- that is, the points closest to and furthest
251
+ * from the screen -- project to the foci of the ellipse.
252
+ *
253
+ * To see this, look at the cone tangent to the sphere whose tip is at
254
+ * the camera. The image of the sphere is the ellipse where this cone
255
+ * intersects the screen. By acting on the sphere with scalings centered
256
+ * on the camera, you can send it to either of the Dandelin spheres that
257
+ * touch the screen at the foci of the image ellipse.
258
+ *
259
+ * This factory method produces two functions, `focusFn(-1)` and
260
+ * `focusFn(1)`, that evaluate to the projections of the front and back
261
+ * points of the sphere, respectively.
262
+ *
263
+ * The parallel projection of a sphere is a cicle. We use an ellipse curve
264
+ * for this projection, too. The two focii now coincide with the center of
265
+ * the sphere. The 2D radius point is defined by the projection of the center
266
+ * and the projected radius.
267
+ * @param {Number} sgn Expecst -1 or 1 for the two focus points
268
+ * @returns {Array} 2D coordinates of the projected focus point
269
+ *
270
+ */
237
271
  focusFn: function (sgn) {
238
272
  var that = this;
239
273
 
240
274
  return function () {
241
- var camDir = that.view.boxToCam[3],
275
+ var camDir,
276
+ v = (that.view.projectionType === 'central') ? 1 : 0,
242
277
  r = that.Radius();
243
278
 
279
+ // Parallel projection: v === 0, the two focii coincide with the center
280
+ // Central projection: v === 1
281
+ camDir = (v === 0) ? [0, 0, 0, 0] : that.view.boxToCam[3];
282
+
244
283
  return that.view.project3DTo2D([
245
- that.center.X() + sgn * r * camDir[1],
246
- that.center.Y() + sgn * r * camDir[2],
247
- that.center.Z() + sgn * r * camDir[3]
284
+ that.center.X() + v * sgn * r * camDir[1],
285
+ that.center.Y() + v * sgn * r * camDir[2],
286
+ that.center.Z() + v * sgn * r * camDir[3]
248
287
  ]).slice(1, 3);
249
288
  };
250
289
  },
251
290
 
291
+ // Replace our 2D representation with a new one that's consistent with
292
+ // the view's current projection type
293
+ /**
294
+ *
295
+ * @returns {Array} 2D coordinates of the projected 3rd point that is on the ellipse.
296
+ */
252
297
  innerVertexFn: function () {
253
298
  var that = this;
254
299
 
@@ -258,6 +303,7 @@ JXG.extend(
258
303
  distOffAxis = Mat.hypot(p[0], p[1]),
259
304
  cam = view.boxToCam,
260
305
  r = that.Radius(),
306
+ c, bs,
261
307
  angleOffAxis = Math.atan(-distOffAxis / p[2]),
262
308
  steepness = Math.acos(r / Mat.norm(p)),
263
309
  lean = angleOffAxis + steepness,
@@ -265,6 +311,22 @@ JXG.extend(
265
311
  sin_lean = Math.sin(lean),
266
312
  inward;
267
313
 
314
+ // Do parallel projection
315
+ if (that.view.projectionType !== 'central') {
316
+ bs = view.bbox3D[0][1] - view.bbox3D[0][0];
317
+ r *= view.size[0] / bs;
318
+
319
+ c = view.project3DTo2D([
320
+ that.center.X(),
321
+ that.center.Y(),
322
+ that.center.Z()
323
+ ]);
324
+ c[1] += r;
325
+
326
+ return c;
327
+ }
328
+
329
+ // Do central projection
268
330
  if (distOffAxis > 1e-8) {
269
331
  // if the center of the sphere isn't too close to the camera
270
332
  // axis, find the direction in plane of the screen that
@@ -289,7 +351,15 @@ JXG.extend(
289
351
  };
290
352
  },
291
353
 
292
- buildCentralProjection: function (attr) {
354
+ /**
355
+ * Create 2D helper points and an ellipse to visualize the `sphere3d`.
356
+ * Handles central and parallel projection simultaneously.
357
+ *
358
+ * This is done only once at creation time.
359
+ *
360
+ * @param {object} attr Attributes for the sphere objects
361
+ */
362
+ buildProjection: function (attr) {
293
363
  var view = this.view,
294
364
  auxStyle = { visible: false, withLabel: false },
295
365
  frontFocus = view.create('point', this.focusFn(-1), auxStyle),
@@ -298,53 +368,6 @@ JXG.extend(
298
368
 
299
369
  this.aux2D = [frontFocus, backFocus, innerVertex];
300
370
  this.element2D = view.create('ellipse', this.aux2D, attr === undefined ? this.visProp : attr);
301
- },
302
-
303
- buildParallelProjection: function (attr) {
304
- // The parallel projection of a sphere is a circle
305
- var that = this,
306
- // center2d = function () {
307
- // var c3d = [1, that.center.X(), that.center.Y(), that.center.Z()];
308
- // return that.view.project3DTo2D(c3d);
309
- // },
310
- radius2d = function () {
311
- var boxSize = that.view.bbox3D[0][1] - that.view.bbox3D[0][0];
312
- return that.Radius() * that.view.size[0] / boxSize;
313
- };
314
-
315
- this.aux2D = [];
316
- this.element2D = this.view.create(
317
- 'circle',
318
- // [center2d, radius2d],
319
- [that.center.element2D, radius2d],
320
- attr === undefined ? this.visProp : attr
321
- );
322
- },
323
-
324
- // replace our 2D representation with a new one that's consistent with
325
- // the view's current projection type
326
- rebuildProjection: function (attr) {
327
- var i;
328
-
329
- // remove the old 2D representation from the scene tree
330
- if (this.element2D) {
331
- this.view.board.removeObject(this.element2D);
332
- for (i in this.aux2D) {
333
- if (this.aux2D.hasOwnProperty(i)) {
334
- this.view.board.removeObject(this.aux2D[i]);
335
- }
336
- }
337
- }
338
-
339
- // build a new 2D representation. the representation is stored in
340
- // `this.element2D`, and any auxiliary elements are stored in
341
- // `this.aux2D`
342
- this.projectionType = this.view.projectionType;
343
- if (this.projectionType === 'central') {
344
- this.buildCentralProjection(attr);
345
- } else {
346
- this.buildParallelProjection(attr);
347
- }
348
371
 
349
372
  // attach the new 2D representation to the scene tree
350
373
  this.addChild(this.element2D);
@@ -638,7 +661,7 @@ JXG.createSphere3D = function (board, parents, attributes) {
638
661
  // to the correct initial state
639
662
  // Here, element2D is created.
640
663
  attr = el.setAttr2D(attr);
641
- el.rebuildProjection(attr);
664
+ el.buildProjection(attr);
642
665
 
643
666
  el.element2D.prepareUpdate().update();
644
667
  if (!board.isSuspendedUpdate) {
package/src/3d/view3d.js CHANGED
@@ -1039,7 +1039,7 @@ JXG.extend(
1039
1039
  },
1040
1040
 
1041
1041
  removeObject: function (object, saveMethod) {
1042
- var i, el, le, o, fst, face;
1042
+ var i, el, le, o, fst, face, gone, list;
1043
1043
 
1044
1044
  // this.board.removeObject(object, saveMethod);
1045
1045
  if (Type.isArray(object)) {
@@ -1051,8 +1051,8 @@ JXG.extend(
1051
1051
 
1052
1052
  object = this.select(object);
1053
1053
 
1054
- // // If the object which is about to be removed unknown or a string, do nothing.
1055
- // // it is a string if a string was given and could not be resolved to an element.
1054
+ // If the object which is about to be removed unknown or a string, do nothing.
1055
+ // it is a string if a string was given and could not be resolved to an element.
1056
1056
  if (!Type.exists(object) || Type.isString(object)) {
1057
1057
  return this;
1058
1058
  }
@@ -1061,38 +1061,46 @@ JXG.extend(
1061
1061
  // Remove all children.
1062
1062
  for (el in object.childElements) {
1063
1063
  if (object.childElements.hasOwnProperty(el)) {
1064
- this.removeObject(object.childElements[el]);
1064
+ o = object.childElements[el];
1065
+ if (!(object.is3D && object.element2D === o)) {
1066
+ this.removeObject(o);
1067
+ }
1065
1068
  }
1066
1069
  }
1067
1070
  if (object.type === Const.OBJECT_TYPE_POLYHEDRON3D) {
1068
1071
  // Special treatment for polyhedron3d.
1069
1072
  // With this we can avoid the time consuming addChild() calls.
1073
+ // Mark faces and their 2D elements, then compact objectsList once.
1074
+ // Splicing face by face with stale _pos removed unrelated elements.
1075
+ gone = {};
1070
1076
  le = object.faces.length;
1071
- if (le > 0) {
1072
- fst = object.faces[0]._pos;
1073
- fst = (object.faces[0].element2D._pos < fst) ? object.faces[0].element2D._pos : fst;
1074
- }
1075
1077
  for (i = 0; i < le; i++) {
1076
1078
  face = object.faces[i];
1077
1079
  delete this.objects[face.id];
1078
1080
 
1079
- // this.board.removeObject(face.element2D, saveMethod);
1080
1081
  delete this.board.objects[face.element2D.id];
1081
1082
  delete this.board.elementsByName[face.element2D.name];
1082
1083
  face.element2D.remove();
1083
- this.board.objectsList.splice(face.element2D._pos, 1);
1084
+ gone[face.element2D.id] = true;
1085
+ face.element2D._pos = -1;
1084
1086
 
1085
1087
  delete this.board.objects[face.id];
1086
1088
  delete this.board.elementsByName[face.name];
1087
1089
  face.remove();
1088
- this.board.objectsList.splice(face._pos, 1);
1090
+ gone[face.id] = true;
1091
+ face._pos = -1;
1089
1092
  }
1090
- le = this.board.objectsList.length;
1091
- // Reindex the positions
1092
- for (i = fst; i < this.board.objectsList.length; i++) {
1093
- o = this.board.objectsList[i];
1094
- if (o._pos > -1) { o._pos = i; }
1093
+ list = this.board.objectsList;
1094
+ fst = 0;
1095
+ for (i = 0; i < list.length; i++) {
1096
+ o = list[i];
1097
+ if (!gone.hasOwnProperty(o.id)) {
1098
+ o._pos = fst;
1099
+ list[fst] = o;
1100
+ fst++;
1101
+ }
1095
1102
  }
1103
+ list.length = fst;
1096
1104
  object.faces = [];
1097
1105
  }
1098
1106
 
package/src/base/board.js CHANGED
@@ -4418,6 +4418,9 @@ JXG.extend(
4418
4418
  var w = width,
4419
4419
  h = height,
4420
4420
  // bb,
4421
+ bbox,
4422
+ offX = 0,
4423
+ offY = 0,
4421
4424
  css,
4422
4425
  width_adjustment, height_adjustment;
4423
4426
 
@@ -4454,7 +4457,38 @@ JXG.extend(
4454
4457
 
4455
4458
  // If bounding box is not yet initialized, do it now.
4456
4459
  if (isNaN(this.getBoundingBox()[0])) {
4457
- this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'keep');
4460
+ // This is not enough
4461
+ // this.setBoundingBox(this.attr.boundingbox, this.keepaspectratio, 'keep');
4462
+ // Instead, we do the same as in JXG.JSXGraphinitBoard():
4463
+ bbox = this.attr.boundingbox;
4464
+ if (Type.exists(bbox) && this.keepaspectratio) {
4465
+ /*
4466
+ * If the boundingbox attribute is given and the ratio of height and width of the
4467
+ * sides defined by the bounding box and the ratio of the dimensions of the div tag
4468
+ * which contains the board do not coincide, then the smaller side is chosen.
4469
+ */
4470
+ this.unitX = w / (bbox[2] - bbox[0]);
4471
+ this.unitY = h / (bbox[1] - bbox[3]);
4472
+
4473
+ if (Math.abs(this.unitX) < Math.abs(this.unitY)) {
4474
+ this.unitY = (Math.abs(this.unitX) * this.unitY) / Math.abs(this.unitY);
4475
+ // Add the additional units in equal portions above and below
4476
+ offY = (h / this.unitY - (bbox[1] - bbox[3])) * 0.5;
4477
+ } else {
4478
+ this.unitX = (Math.abs(this.unitY) * this.unitX) / Math.abs(this.unitX);
4479
+ // Add the additional units in equal portions left and right
4480
+ offX = (w / this.unitX - (bbox[2] - bbox[0])) * 0.5;
4481
+ }
4482
+ } else {
4483
+ this.unitX = w / (bbox[2] - bbox[0]);
4484
+ this.unitY = h / (bbox[1] - bbox[3]);
4485
+ }
4486
+ this.origin.scrCoords = [1,
4487
+ -this.unitX * (bbox[0] - offX),
4488
+ this.unitY * (bbox[1] + offY)
4489
+ ];
4490
+ this.canvasWidth = w;
4491
+ this.canvasHeight = h;
4458
4492
  }
4459
4493
 
4460
4494
  // Do nothing if the dimension did not change since being visible
@@ -4495,16 +4529,21 @@ JXG.extend(
4495
4529
  }
4496
4530
 
4497
4531
  this.resizeObserver = new ResizeObserver(function (entries) {
4498
- var bb;
4532
+ // var bb;
4533
+
4534
+ // Take the last observed size
4535
+ that._lastContentRect = entries[entries.length - 1].contentRect;
4499
4536
  if (!that._isResizing) {
4500
4537
  that._isResizing = true;
4501
- bb = entries[0].contentRect;
4538
+ // bb = entries[0].contentRect;
4502
4539
  window.setTimeout(function () {
4540
+ var bb = that._lastContentRect;
4503
4541
  try {
4504
4542
  that.updateContainerDims(bb.width, bb.height);
4505
4543
  } catch (e) {
4506
- JXG.debug(e); // Used to log errors during board.update()
4507
- that.stopResizeObserver();
4544
+ // JXG.debug(e); // Used to log errors during board.update()
4545
+ console.error(e);
4546
+ // that.stopResizeObserver();
4508
4547
  } finally {
4509
4548
  that._isResizing = false;
4510
4549
  }
@@ -5537,7 +5576,7 @@ JXG.extend(
5537
5576
  * @private
5538
5577
  */
5539
5578
  _removeObj: function (object, saveMethod) {
5540
- var el, o, i;
5579
+ var el, i, pos;
5541
5580
 
5542
5581
  if (Type.isArray(object)) {
5543
5582
  for (i = 0; i < object.length; i++) {
@@ -5555,6 +5594,16 @@ JXG.extend(
5555
5594
  return this;
5556
5595
  }
5557
5596
 
5597
+ // Already removed (e.g. reached again through a parent's childElements
5598
+ // or View3D.removeObject). Removing it twice used to splice a live element.
5599
+ if (object._pos === -1 && this.objects[object.id] !== object) {
5600
+ return this;
5601
+ }
5602
+
5603
+ if (object.is3D && Type.exists(object.view.objects[object.id])) {
5604
+ JXG.warn("board.removeObject() of 3D object " + object.id + ". Use view3d.removeObject() instead.");
5605
+ }
5606
+
5558
5607
  try {
5559
5608
  // remove all children.
5560
5609
  for (el in object.childElements) {
@@ -5604,15 +5653,16 @@ JXG.extend(
5604
5653
  }
5605
5654
 
5606
5655
  // remove the object itself from our control structures
5607
- if (object._pos > -1) {
5608
- this.objectsList.splice(object._pos, 1);
5656
+ // Trust _pos only if it still points at the object, and reset it
5657
+ // afterwards, so a stale index can never splice another element.
5658
+ pos = this.objectsList[object._pos] === object ? object._pos : this.objectsList.indexOf(object);
5659
+ if (pos > -1) {
5660
+ this.objectsList.splice(pos, 1);
5609
5661
  // Quadratic complexity for reindexing the positions:
5610
- for (i = object._pos; i < this.objectsList.length; i++) {
5611
- o = this.objectsList[i];
5612
- if (o._pos > -1) {
5613
- o._pos--;
5614
- }
5662
+ for (i = pos; i < this.objectsList.length; i++) {
5663
+ this.objectsList[i]._pos = i;
5615
5664
  }
5665
+ object._pos = -1;
5616
5666
  } else if (object.type !== Const.OBJECT_TYPE_TURTLE) {
5617
5667
  JXG.debug(
5618
5668
  'Board.removeObject: object ' + object.id + ' not found in list.'
@@ -180,9 +180,9 @@ JXG.extend(
180
180
  /** @lends JXG.Composition.prototype */ {
181
181
  /**
182
182
  * Adds an element to the composition container.
183
- * @param {String} what Descriptive name for the element, e.g. <em>startpoint</em> or <em>area</em>. This is used to
184
- * access the element later on. There are some reserved names: <em>elements, add, remove, update, prepareUpdate,
185
- * updateRenderer, highlight, noHighlight</em>, and all names that would form invalid object property names in
183
+ * @param {String} what Descriptive name for the element, e.g. `startpoint` or `area`. This is used to
184
+ * access the element later on. There are some reserved names: `elements`, `add`, `remove`, `update`, `prepareUpdate`,
185
+ * `updateRenderer`, `highlight`, `noHighlight`, and all names that would form invalid object property names in
186
186
  * JavaScript.
187
187
  * @param {JXG.GeometryElement|JXG.Composition} element A reference to the element that is to be added. This can be
188
188
  * another composition, too.
@@ -37,7 +37,7 @@ import JXG from "../jxg.js";
37
37
 
38
38
  var major = 1,
39
39
  minor = 14,
40
- patch = 0,
40
+ patch = 1,
41
41
  add = '', // 'dev' 'beta1'
42
42
  version = major + '.' + minor + '.' + patch + (add ? '-' + add : ''),
43
43
  constants;
@@ -2468,7 +2468,8 @@ JXG.extend(
2468
2468
  } else if (this.elementClass === Const.OBJECT_CLASS_CIRCLE) {
2469
2469
  x = this.center.X();
2470
2470
  y = this.center.Y();
2471
- bb = [x - this.radius, y + this.radius, x + this.radius, y - this.radius];
2471
+ r = this.Radius(); // this.radius
2472
+ bb = [x - r, y + r, x + r, y - r];
2472
2473
  } else if (this.elementClass === Const.OBJECT_CLASS_CURVE) {
2473
2474
  le = this.points.length;
2474
2475
  if (le === 0) {
package/src/base/text.js CHANGED
@@ -1761,8 +1761,8 @@ JXG.createHTMLSlider = function (board, parents, attributes) {
1761
1761
  }
1762
1762
 
1763
1763
  // Backwards compatibility
1764
- attr.anchor = attr.parent || attr.anchor;
1765
- attr.fixed = attr.fixed || true;
1764
+ attr.anchor = Type.def(attr.parent, attr.anchor);
1765
+ attr.fixed = Type.def(attr.fixed, true);
1766
1766
 
1767
1767
  par = [
1768
1768
  parents[0][0],
@@ -119,13 +119,30 @@ import Type from "../utils/type.js";
119
119
  * @jsxgraphsignature Ellipse
120
120
  * Parent elements can be two elements either of type {@link JXG.Point} or array of
121
121
  * numbers describing the coordinates of a point.
122
- * The third parameter is a number/function which defines the length of the major axis
122
+ * The third parameter is a number/function which defines the length of the major axis.
123
123
  * @param {PointLike} point1
124
124
  * @param {PointLike} point2
125
125
  * @param {NumberLike} number
126
126
  * @param {Number} [start=0] parameter of the curve start, default: 0.
127
127
  * @param {Number} [end=2π] parameter for the curve end, default: 2&pi;.
128
128
  *
129
+ * @example
130
+ * var A = board.create('point', [1,0]);
131
+ * var B = board.create('point', [-1,0]);
132
+ * var el = board.create('ellipse',[A, B, 4]);
133
+ *
134
+ * </pre><div id="JXG7898d447-94dc-4dce-9ad3-60e3387be9f3" class="jxgbox" style="width: 300px; height: 300px;"></div>
135
+ * <script type="text/javascript">
136
+ * (function() {
137
+ * var board = JXG.JSXGraph.initBoard('JXG7898d447-94dc-4dce-9ad3-60e3387be9f3',
138
+ * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
139
+ * var A = board.create('point', [1,0]);
140
+ * var B = board.create('point', [-1,0]);
141
+ * var el = board.create('ellipse',[A,B, 4]);
142
+ * })();
143
+ *
144
+ * </script><pre>
145
+ *
129
146
  */
130
147
  JXG.createEllipse = function (board, parents, attributes) {
131
148
  var polarForm,
@@ -397,6 +414,23 @@ JXG.createEllipse = function (board, parents, attributes) {
397
414
  * @param {NumberLike} number
398
415
  * @param {Number} [start=-π] parameter of the curve start, default: -&pi;.
399
416
  * @param {Number} [end=π] parameter for the curve end, default: &pi;.
417
+ * @example
418
+ * var A = board.create('point', [1,0]);
419
+ * var B = board.create('point', [-1,0]);
420
+ * var el = board.create('hyperbola',[A, B, 1]);
421
+ *
422
+ * </pre><div id="JXGa4c0068b-41bc-4be4-b485-d0d0c7f2e10b" class="jxgbox" style="width: 300px; height: 300px;"></div>
423
+ * <script type="text/javascript">
424
+ * (function() {
425
+ * var board = JXG.JSXGraph.initBoard('JXGa4c0068b-41bc-4be4-b485-d0d0c7f2e10b',
426
+ * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
427
+ * var A = board.create('point', [1,0]);
428
+ * var B = board.create('point', [-1,0]);
429
+ * var el = board.create('hyperbola',[A,B, 1]);
430
+ *
431
+ * })();
432
+ *
433
+ * </script><pre>
400
434
  */
401
435
  JXG.createHyperbola = function (board, parents, attributes) {
402
436
  var polarForm,