@woosh/meep-engine 2.118.5 → 2.118.6
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/build/meep.cjs +520 -479
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +520 -479
- package/package.json +4 -4
- package/src/core/binary/BitSet.d.ts +0 -5
- package/src/core/binary/BitSet.d.ts.map +1 -1
- package/src/core/binary/BitSet.js +2 -10
- package/src/core/binary/base64/Base64.d.ts.map +1 -0
- package/src/core/binary/largest_common_alignment_uint32.d.ts.map +1 -0
- package/src/core/{collection/array/typed → binary}/largest_common_alignment_uint32.js +1 -1
- package/src/core/collection/CuckooFilter.d.ts +34 -8
- package/src/core/collection/CuckooFilter.d.ts.map +1 -1
- package/src/core/collection/CuckooFilter.js +29 -1
- package/src/core/collection/array/typed/array_buffer_copy.d.ts.map +1 -1
- package/src/core/collection/array/typed/array_buffer_copy.js +3 -1
- package/src/core/collection/array/typed/is_array_buffer_equals.js +1 -1
- package/src/core/collection/array/typed/is_typed_array_equals.js +1 -1
- package/src/core/collection/map/HashMap.js +7 -7
- package/src/core/geom/2d/aabb/AABB2.d.ts.map +1 -1
- package/src/core/geom/2d/aabb/AABB2.js +43 -22
- package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.d.ts.map +1 -1
- package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.js +6 -1
- package/src/core/geom/2d/quad-tree/QuadTreeDatum.d.ts +3 -5
- package/src/core/geom/2d/quad-tree/QuadTreeDatum.d.ts.map +1 -1
- package/src/core/geom/2d/quad-tree/QuadTreeDatum.js +9 -19
- package/src/core/geom/2d/rectangle_to_aabb.d.ts +8 -0
- package/src/core/geom/2d/rectangle_to_aabb.d.ts.map +1 -0
- package/src/core/geom/2d/rectangle_to_aabb.js +29 -0
- package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +1 -1
- package/src/core/graph/graph_compute_distance_matrix.d.ts +1 -1
- package/src/core/graph/graph_compute_distance_matrix.d.ts.map +1 -1
- package/src/core/graph/graph_compute_distance_matrix.js +1 -1
- package/src/core/graph/graph_compute_laplacian_matrix.d.ts +1 -1
- package/src/core/graph/graph_compute_laplacian_matrix.d.ts.map +1 -1
- package/src/core/graph/graph_compute_laplacian_matrix.js +1 -1
- package/src/core/graph/layout/CircleLayout.js +2 -2
- package/src/core/graph/layout/box/BoxLayouter.d.ts.map +1 -1
- package/src/core/graph/layout/box/BoxLayouter.js +11 -5
- package/src/core/graph/layout/box/aabb2_force_into_container.d.ts +7 -0
- package/src/core/graph/layout/box/aabb2_force_into_container.d.ts.map +1 -0
- package/src/core/graph/layout/box/aabb2_force_into_container.js +56 -0
- package/src/core/graph/layout/box/applyCentralGravityAABB2.d.ts.map +1 -1
- package/src/core/graph/layout/box/applyCentralGravityAABB2.js +2 -8
- package/src/core/graph/layout/box/forceIntoBox.d.ts +4 -2
- package/src/core/graph/layout/box/forceIntoBox.d.ts.map +1 -1
- package/src/core/graph/layout/box/forceIntoBox.js +5 -31
- package/src/core/graph/layout/box/position_box_next_to_box.d.ts +10 -0
- package/src/core/graph/layout/box/position_box_next_to_box.d.ts.map +1 -0
- package/src/core/graph/layout/box/position_box_next_to_box.js +218 -0
- package/src/core/graph/layout/box/pullBoxTowardsPoint.d.ts.map +1 -1
- package/src/core/graph/layout/box/pullBoxTowardsPoint.js +8 -3
- package/src/core/graph/layout/box/resolveAABB2Overlap.d.ts +2 -2
- package/src/core/graph/layout/box/resolveAABB2Overlap.d.ts.map +1 -1
- package/src/core/graph/layout/box/resolveAABB2Overlap.js +12 -4
- package/src/core/graph/layout/box/resolveBoxOverlapUsingForce.d.ts +1 -0
- package/src/core/graph/layout/box/resolveBoxOverlapUsingForce.d.ts.map +1 -1
- package/src/core/graph/layout/box/resolveBoxOverlapUsingForce.js +1 -0
- package/src/core/math/matrix/SquareMatrix.d.ts.map +1 -0
- package/src/core/{graph → math/matrix}/SquareMatrix.js +3 -3
- package/src/core/math/spline/cubicCurve.d.ts +3 -8
- package/src/core/math/spline/cubicCurve.d.ts.map +1 -1
- package/src/core/math/spline/cubicCurve.js +4 -32
- package/src/core/model/reactive/js/compileReactiveToJS.d.ts.map +1 -1
- package/src/core/model/reactive/js/compileReactiveToJS.js +56 -1
- package/src/core/model/reactive/model/terminal/ReactiveReference.d.ts.map +1 -1
- package/src/core/model/reactive/model/terminal/ReactiveReference.js +2 -2
- package/src/core/model/reactive/trigger/ReactiveTrigger.d.ts +2 -2
- package/src/core/model/reactive/trigger/ReactiveTrigger.d.ts.map +1 -1
- package/src/core/model/reactive/trigger/ReactiveTrigger.js +1 -1
- package/src/core/process/BaseProcess.d.ts.map +1 -1
- package/src/core/process/BaseProcess.js +8 -7
- package/src/core/process/SimpleLifecycle.d.ts +5 -0
- package/src/core/process/SimpleLifecycle.d.ts.map +1 -1
- package/src/core/process/SimpleLifecycle.js +8 -0
- package/src/core/process/task/Task.js +1 -1
- package/src/engine/animation/clip/AnimationClip.d.ts.map +1 -1
- package/src/engine/animation/clip/AnimationClip.js +50 -8
- package/src/engine/animation/clip/AnimationClipBinding.js +1 -1
- package/src/engine/animation/clip/AnimationTrack.d.ts +11 -1
- package/src/engine/animation/clip/AnimationTrack.d.ts.map +1 -1
- package/src/engine/animation/clip/AnimationTrack.js +50 -7
- package/src/engine/animation/curve/binding/BoundPlainNumericPropertyWriter.d.ts +8 -0
- package/src/engine/animation/curve/binding/BoundPlainNumericPropertyWriter.d.ts.map +1 -0
- package/src/engine/animation/curve/binding/BoundPlainNumericPropertyWriter.js +16 -0
- package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/splat/SplatMapping.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +6 -6
- package/src/engine/graphics/texture/sampler/Sampler2D.js +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts +3 -3
- package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts.map +1 -1
- package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +6 -6
- package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.d.ts.map +1 -1
- package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +35 -31
- package/src/generation/grid/generation/grid/GridTaskAddNodesFixed.d.ts.map +1 -1
- package/src/generation/grid/generation/grid/GridTaskAddNodesFixed.js +8 -11
- package/src/generation/grid/generation/road/RoadConnectionNetwork.d.ts +6 -2
- package/src/generation/grid/generation/road/RoadConnectionNetwork.d.ts.map +1 -1
- package/src/generation/grid/generation/road/RoadConnectionNetwork.js +36 -30
- package/src/generation/placement/action/GridCellAction.js +1 -1
- package/src/generation/theme/AreaTheme.d.ts.map +1 -1
- package/src/generation/theme/AreaTheme.js +0 -1
- package/src/generation/theme/TerrainLayerRule.d.ts.map +1 -1
- package/src/generation/theme/TerrainLayerRule.js +2 -1
- package/src/generation/theme/TerrainLayerRuleAggregator.d.ts +5 -1
- package/src/generation/theme/TerrainLayerRuleAggregator.d.ts.map +1 -1
- package/src/generation/theme/TerrainLayerRuleAggregator.js +7 -2
- package/src/generation/theme/ThemeEngine.d.ts +2 -2
- package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
- package/src/generation/theme/ThemeEngine.js +1 -4
- package/src/generation/theme/cell/CellProcessingRule.d.ts.map +1 -1
- package/src/generation/theme/cell/CellProcessingRule.js +10 -13
- package/src/generation/theme/cell/CellProcessingRuleSet.d.ts.map +1 -1
- package/src/generation/theme/cell/CellProcessingRuleSet.js +6 -7
- package/src/view/SVG.d.ts.map +1 -1
- package/src/view/SVG.js +0 -15
- package/src/view/html_element_to_aabb.d.ts +8 -0
- package/src/view/html_element_to_aabb.d.ts.map +1 -0
- package/src/view/html_element_to_aabb.js +29 -0
- package/src/view/tooltip/TooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/TooltipManager.js +7 -9
- package/src/view/tooltip/TooltipView.d.ts +0 -1
- package/src/view/tooltip/TooltipView.d.ts.map +1 -1
- package/src/view/tooltip/TooltipView.js +10 -280
- package/src/view/tooltip/gml/TooltipParser.d.ts.map +1 -1
- package/src/view/tooltip/gml/TooltipParser.js +1 -13
- package/src/core/binary/Base64.d.ts.map +0 -1
- package/src/core/collection/array/typed/largest_common_alignment_uint32.d.ts.map +0 -1
- package/src/core/graph/SquareMatrix.d.ts.map +0 -1
- package/src/engine/simulation/DormandPrince.d.ts +0 -19
- package/src/engine/simulation/DormandPrince.d.ts.map +0 -1
- package/src/engine/simulation/DormandPrince.js +0 -242
- /package/src/core/binary/{Base64.d.ts → base64/Base64.d.ts} +0 -0
- /package/src/core/binary/{Base64.js → base64/Base64.js} +0 -0
- /package/src/core/{collection/array/typed → binary}/largest_common_alignment_uint32.d.ts +0 -0
- /package/src/core/{graph → math/matrix}/SquareMatrix.d.ts +0 -0
package/build/meep.module.js
CHANGED
|
@@ -60347,15 +60347,15 @@ class HashMap {
|
|
|
60347
60347
|
|
|
60348
60348
|
this.__entries_bound++;
|
|
60349
60349
|
|
|
60350
|
-
|
|
60350
|
+
const existing_entry = this.__entries[i];
|
|
60351
60351
|
|
|
60352
|
-
|
|
60352
|
+
if (existing_entry !== undefined) {
|
|
60353
60353
|
|
|
60354
|
-
|
|
60354
|
+
// entry exists, let's reuse it
|
|
60355
60355
|
|
|
60356
|
-
|
|
60357
|
-
|
|
60358
|
-
|
|
60356
|
+
existing_entry.hash = hash;
|
|
60357
|
+
existing_entry.key = k;
|
|
60358
|
+
existing_entry.value = v;
|
|
60359
60359
|
|
|
60360
60360
|
} else {
|
|
60361
60361
|
|
|
@@ -64355,7 +64355,7 @@ class Task {
|
|
|
64355
64355
|
* Run entire task synchronously to completion
|
|
64356
64356
|
*/
|
|
64357
64357
|
executeSync() {
|
|
64358
|
-
this.initialize();
|
|
64358
|
+
this.initialize(this,null);
|
|
64359
64359
|
|
|
64360
64360
|
this.on.started.send0();
|
|
64361
64361
|
|
|
@@ -71111,7 +71111,7 @@ const GROW_FACTOR$1 = 1.3;
|
|
|
71111
71111
|
* @constant
|
|
71112
71112
|
* @type {number}
|
|
71113
71113
|
*/
|
|
71114
|
-
const
|
|
71114
|
+
const DEFAULT_SHRINK_FACTOR = 0.5;
|
|
71115
71115
|
|
|
71116
71116
|
/**
|
|
71117
71117
|
* Minimum number of bits to increase the capacity by
|
|
@@ -71157,7 +71157,7 @@ class BitSet {
|
|
|
71157
71157
|
/**
|
|
71158
71158
|
* @type {number}
|
|
71159
71159
|
*/
|
|
71160
|
-
this.__shrinkFactor =
|
|
71160
|
+
this.__shrinkFactor = DEFAULT_SHRINK_FACTOR;
|
|
71161
71161
|
}
|
|
71162
71162
|
|
|
71163
71163
|
preventShrink() {
|
|
@@ -71500,14 +71500,6 @@ class BitSet {
|
|
|
71500
71500
|
}
|
|
71501
71501
|
}
|
|
71502
71502
|
|
|
71503
|
-
/**
|
|
71504
|
-
*
|
|
71505
|
-
* @param {BitSet} set
|
|
71506
|
-
*/
|
|
71507
|
-
and(set) {
|
|
71508
|
-
throw new Error("NIY");
|
|
71509
|
-
}
|
|
71510
|
-
|
|
71511
71503
|
/**
|
|
71512
71504
|
* Returns the value of the bit with the specified index.
|
|
71513
71505
|
* @param {int} bitIndex
|
|
@@ -78935,13 +78927,13 @@ const ProcessState = {
|
|
|
78935
78927
|
class BaseProcess {
|
|
78936
78928
|
|
|
78937
78929
|
id = "";
|
|
78930
|
+
|
|
78938
78931
|
/**
|
|
78939
78932
|
* @readonly
|
|
78940
78933
|
* @type {ObservedEnum.<ProcessState>}
|
|
78941
78934
|
*/
|
|
78942
78935
|
__state = new ObservedEnum(ProcessState.New, ProcessState);
|
|
78943
78936
|
|
|
78944
|
-
|
|
78945
78937
|
/**
|
|
78946
78938
|
* @returns {ObservedEnum<ProcessState>}
|
|
78947
78939
|
*/
|
|
@@ -78951,10 +78943,10 @@ class BaseProcess {
|
|
|
78951
78943
|
|
|
78952
78944
|
initialize() {
|
|
78953
78945
|
|
|
78954
|
-
const
|
|
78946
|
+
const state_current = this.__state.getValue();
|
|
78955
78947
|
|
|
78956
|
-
if (
|
|
78957
|
-
throw new IllegalStateException(`Expected New or Finalized state, instead got ${objectKeyByValue(ProcessState,
|
|
78948
|
+
if (state_current !== ProcessState.New && state_current !== ProcessState.Finalized) {
|
|
78949
|
+
throw new IllegalStateException(`Expected New or Finalized state, instead got ${objectKeyByValue(ProcessState, state_current)}`);
|
|
78958
78950
|
}
|
|
78959
78951
|
|
|
78960
78952
|
|
|
@@ -78969,6 +78961,7 @@ class BaseProcess {
|
|
|
78969
78961
|
this.shutdown();
|
|
78970
78962
|
}
|
|
78971
78963
|
|
|
78964
|
+
// note that we don't bind state value, because it is liable to change in "shutdown"
|
|
78972
78965
|
if (state.getValue() !== ProcessState.Stopped && state.getValue() !== ProcessState.Initialized) {
|
|
78973
78966
|
throw new IllegalStateException(`Expected Initialized or Stopped state, instead got ${objectKeyByValue(ProcessState, state.getValue())}`);
|
|
78974
78967
|
}
|
|
@@ -78977,10 +78970,10 @@ class BaseProcess {
|
|
|
78977
78970
|
}
|
|
78978
78971
|
|
|
78979
78972
|
startup() {
|
|
78980
|
-
const
|
|
78973
|
+
const state_current = this.__state.getValue();
|
|
78981
78974
|
|
|
78982
|
-
if (
|
|
78983
|
-
throw new IllegalStateException(`Expected Initial state, instead got ${objectKeyByValue(ProcessState,
|
|
78975
|
+
if (state_current !== ProcessState.Initialized && state_current !== ProcessState.Stopped) {
|
|
78976
|
+
throw new IllegalStateException(`Expected Initial state, instead got ${objectKeyByValue(ProcessState, state_current)}`);
|
|
78984
78977
|
}
|
|
78985
78978
|
|
|
78986
78979
|
this.__state.set(ProcessState.Running);
|
|
@@ -80833,22 +80826,6 @@ class AABB2 {
|
|
|
80833
80826
|
this._expandToFit(x, y, x, y);
|
|
80834
80827
|
}
|
|
80835
80828
|
|
|
80836
|
-
/**
|
|
80837
|
-
* retrieve midpoint of AABB along X axis
|
|
80838
|
-
* @returns {number}
|
|
80839
|
-
*/
|
|
80840
|
-
midX() {
|
|
80841
|
-
return (this.x1 + this.x0) / 2;
|
|
80842
|
-
}
|
|
80843
|
-
|
|
80844
|
-
/**
|
|
80845
|
-
* retrieve midpoint of AABB along Y axis
|
|
80846
|
-
* @returns {number}
|
|
80847
|
-
*/
|
|
80848
|
-
midY() {
|
|
80849
|
-
return (this.y1 + this.y0) / 2;
|
|
80850
|
-
}
|
|
80851
|
-
|
|
80852
80829
|
/**
|
|
80853
80830
|
* NOTE: only 1 intersection point is produced
|
|
80854
80831
|
* @param {Vector2} p0
|
|
@@ -81000,16 +80977,35 @@ class AABB2 {
|
|
|
81000
80977
|
|
|
81001
80978
|
/**
|
|
81002
80979
|
*
|
|
81003
|
-
* @param {Vector2} result
|
|
80980
|
+
* @param {Vector2} [result]
|
|
81004
80981
|
*/
|
|
81005
80982
|
getCenter(result = new Vector2()) {
|
|
80983
|
+
|
|
81006
80984
|
result.set(this.centerX, this.centerY);
|
|
81007
80985
|
|
|
81008
80986
|
return result;
|
|
81009
80987
|
}
|
|
81010
80988
|
|
|
81011
80989
|
/**
|
|
81012
|
-
*
|
|
80990
|
+
* retrieve midpoint of AABB along X axis
|
|
80991
|
+
* @deprecated use {@link centerX} instead
|
|
80992
|
+
* @returns {number}
|
|
80993
|
+
*/
|
|
80994
|
+
midX() {
|
|
80995
|
+
return this.centerX;
|
|
80996
|
+
}
|
|
80997
|
+
|
|
80998
|
+
/**
|
|
80999
|
+
* retrieve midpoint of AABB along Y axis
|
|
81000
|
+
* @deprecated use {@link centerY} instead
|
|
81001
|
+
* @returns {number}
|
|
81002
|
+
*/
|
|
81003
|
+
midY() {
|
|
81004
|
+
return this.centerY;
|
|
81005
|
+
}
|
|
81006
|
+
|
|
81007
|
+
/**
|
|
81008
|
+
* midpoint along X axis
|
|
81013
81009
|
* @return {number}
|
|
81014
81010
|
*/
|
|
81015
81011
|
get centerX() {
|
|
@@ -81017,7 +81013,7 @@ class AABB2 {
|
|
|
81017
81013
|
}
|
|
81018
81014
|
|
|
81019
81015
|
/**
|
|
81020
|
-
*
|
|
81016
|
+
* midpoint along Y axis
|
|
81021
81017
|
* @return {number}
|
|
81022
81018
|
*/
|
|
81023
81019
|
get centerY() {
|
|
@@ -81093,7 +81089,10 @@ class AABB2 {
|
|
|
81093
81089
|
* @param {number} deltaY
|
|
81094
81090
|
*/
|
|
81095
81091
|
move(deltaX, deltaY) {
|
|
81096
|
-
this.set(
|
|
81092
|
+
this.set(
|
|
81093
|
+
this.x0 + deltaX, this.y0 + deltaY,
|
|
81094
|
+
this.x1 + deltaX, this.y1 + deltaY
|
|
81095
|
+
);
|
|
81097
81096
|
}
|
|
81098
81097
|
|
|
81099
81098
|
/**
|
|
@@ -81192,6 +81191,21 @@ class AABB2 {
|
|
|
81192
81191
|
fromJSON(json) {
|
|
81193
81192
|
this.set(json.x0, json.y0, json.x1, json.y1);
|
|
81194
81193
|
}
|
|
81194
|
+
|
|
81195
|
+
/**
|
|
81196
|
+
* @param {number[]|Float32Array} target
|
|
81197
|
+
* @param {number} offset
|
|
81198
|
+
* @returns {number[]|Float32Array}
|
|
81199
|
+
*/
|
|
81200
|
+
toArray(target=[], offset=0){
|
|
81201
|
+
|
|
81202
|
+
target[offset] = this.x0;
|
|
81203
|
+
target[offset+1] = this.y0;
|
|
81204
|
+
target[offset+2] = this.x1;
|
|
81205
|
+
target[offset+3] = this.y1;
|
|
81206
|
+
|
|
81207
|
+
return target;
|
|
81208
|
+
}
|
|
81195
81209
|
}
|
|
81196
81210
|
|
|
81197
81211
|
|
|
@@ -81205,8 +81219,8 @@ class AABB2 {
|
|
|
81205
81219
|
*/
|
|
81206
81220
|
function computeLineBetweenTwoBoxes(b0, b1, p0, p1) {
|
|
81207
81221
|
//compute box centers
|
|
81208
|
-
const c0 = new Vector2(b0.
|
|
81209
|
-
const c1 = new Vector2(b1.
|
|
81222
|
+
const c0 = new Vector2(b0.centerX, b0.centerY);
|
|
81223
|
+
const c1 = new Vector2(b1.centerX, b1.centerY);
|
|
81210
81224
|
|
|
81211
81225
|
const i0 = b0.lineIntersectionPoint(c0, c1, p0);
|
|
81212
81226
|
|
|
@@ -97728,6 +97742,14 @@ class SimpleLifecycle {
|
|
|
97728
97742
|
this.priority = priority;
|
|
97729
97743
|
}
|
|
97730
97744
|
|
|
97745
|
+
/**
|
|
97746
|
+
*
|
|
97747
|
+
* @returns {SimpleLifecycleStateType}
|
|
97748
|
+
*/
|
|
97749
|
+
get state(){
|
|
97750
|
+
return this.sm.getState();
|
|
97751
|
+
}
|
|
97752
|
+
|
|
97731
97753
|
makeReady() {
|
|
97732
97754
|
const s = this.sm.getState();
|
|
97733
97755
|
if (s === SimpleLifecycleStateType.Ready) {
|
|
@@ -100304,20 +100326,8 @@ class TooltipParser {
|
|
|
100304
100326
|
*/
|
|
100305
100327
|
parse(code) {
|
|
100306
100328
|
|
|
100307
|
-
|
|
100329
|
+
return this.#cache.getOrCompute(code, parseTooltipString);
|
|
100308
100330
|
|
|
100309
|
-
if (existing !== null) {
|
|
100310
|
-
// result is cached, reuse
|
|
100311
|
-
return existing;
|
|
100312
|
-
}
|
|
100313
|
-
|
|
100314
|
-
// no cached result, parse
|
|
100315
|
-
const tokens = parseTooltipString(code);
|
|
100316
|
-
|
|
100317
|
-
// cache result
|
|
100318
|
-
this.#cache.put(code, tokens);
|
|
100319
|
-
|
|
100320
|
-
return tokens;
|
|
100321
100331
|
}
|
|
100322
100332
|
}
|
|
100323
100333
|
|
|
@@ -100848,146 +100858,95 @@ class GMLEngine {
|
|
|
100848
100858
|
|
|
100849
100859
|
}
|
|
100850
100860
|
|
|
100851
|
-
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
100852
|
-
|
|
100853
100861
|
/**
|
|
100854
100862
|
*
|
|
100855
|
-
* @param {
|
|
100856
|
-
* @
|
|
100857
|
-
* @param {number} a0 starting angle
|
|
100858
|
-
* @param {number} a1 end angle
|
|
100859
|
-
* @returns {string}
|
|
100860
|
-
*/
|
|
100861
|
-
function svgArc(r0, r1, a0, a1) {
|
|
100862
|
-
let da, df;
|
|
100863
|
-
const c0 = Math.cos(a0);
|
|
100864
|
-
const s0 = Math.sin(a0);
|
|
100865
|
-
const c1 = Math.cos(a1);
|
|
100866
|
-
const s1 = Math.sin(a1);
|
|
100867
|
-
|
|
100868
|
-
da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0);
|
|
100869
|
-
|
|
100870
|
-
df = da < Math.PI ? "0" : "1";
|
|
100871
|
-
|
|
100872
|
-
return "M" + r1 * c0 + "," + r1 * s0
|
|
100873
|
-
+ "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1
|
|
100874
|
-
+ "L" + r0 * c1 + "," + r0 * s1
|
|
100875
|
-
+ "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0
|
|
100876
|
-
+ "Z";
|
|
100877
|
-
}
|
|
100878
|
-
|
|
100879
|
-
/**
|
|
100880
|
-
*
|
|
100881
|
-
* @param {number} r0 Inner radius
|
|
100882
|
-
* @param {number} r1 Outer Radius
|
|
100883
|
-
* @param {number} a0 Start of the inner arc (in rad)
|
|
100884
|
-
* @param {number} b0 End of the inner arc (in rad)
|
|
100885
|
-
* @param {number} a1 Start of the outer arc (in rad)
|
|
100886
|
-
* @param {number} b1 End of the outer arc (in rad)
|
|
100887
|
-
* @returns {string}
|
|
100863
|
+
* @param {Rectangle} rect
|
|
100864
|
+
* @returns {AABB2}
|
|
100888
100865
|
*/
|
|
100889
|
-
function
|
|
100890
|
-
const
|
|
100891
|
-
const as0 = Math.sin(a0);
|
|
100866
|
+
function rectangle_to_aabb(rect) {
|
|
100867
|
+
const position = rect.position;
|
|
100892
100868
|
|
|
100893
|
-
const
|
|
100894
|
-
const
|
|
100869
|
+
const x0 = position.x;
|
|
100870
|
+
const y0 = position.y;
|
|
100895
100871
|
|
|
100896
|
-
const
|
|
100897
|
-
const as1 = Math.sin(a1);
|
|
100872
|
+
const size = rect.size;
|
|
100898
100873
|
|
|
100899
|
-
|
|
100900
|
-
|
|
100874
|
+
let x1 = x0;
|
|
100875
|
+
let y1 = y0;
|
|
100901
100876
|
|
|
100902
|
-
|
|
100903
|
-
|
|
100877
|
+
// sanitize bounds
|
|
100878
|
+
if (size.x > 0) {
|
|
100879
|
+
x1 += size.x;
|
|
100880
|
+
}
|
|
100904
100881
|
|
|
100905
|
-
|
|
100906
|
-
|
|
100907
|
-
|
|
100908
|
-
L${r0 * bc0},${r0 * bs0}
|
|
100909
|
-
A${r0},${r0} 0 ${largeArcFlag0},0 ${r0 * ac0},${r0 * as0}
|
|
100910
|
-
Z
|
|
100911
|
-
`;
|
|
100912
|
-
}
|
|
100882
|
+
if (size.y > 0) {
|
|
100883
|
+
y1 += size.y;
|
|
100884
|
+
}
|
|
100913
100885
|
|
|
100886
|
+
return new AABB2(x0, y0, x1, y1);
|
|
100887
|
+
}
|
|
100888
|
+
|
|
100914
100889
|
/**
|
|
100915
100890
|
*
|
|
100916
|
-
* @param {
|
|
100917
|
-
* @
|
|
100918
|
-
|
|
100919
|
-
|
|
100920
|
-
|
|
100921
|
-
|
|
100922
|
-
|
|
100923
|
-
|
|
100924
|
-
|
|
100925
|
-
|
|
100926
|
-
createElement: createSVGElement
|
|
100927
|
-
};
|
|
100928
|
-
|
|
100929
|
-
class CompassArrowView extends View {
|
|
100930
|
-
constructor() {
|
|
100931
|
-
super();
|
|
100932
|
-
|
|
100933
|
-
|
|
100934
|
-
const elSVG = SVG.createElement('svg');
|
|
100935
|
-
|
|
100936
|
-
const elDefs = SVG.createElement('defs');
|
|
100937
|
-
const elGradient = SVG.createElement('linearGradient');
|
|
100938
|
-
elGradient.setAttribute('id', 'gradient');
|
|
100939
|
-
|
|
100940
|
-
elDefs.appendChild(elGradient);
|
|
100941
|
-
const elStop0 = SVG.createElement('stop');
|
|
100942
|
-
const elStop1 = SVG.createElement('stop');
|
|
100943
|
-
|
|
100944
|
-
elStop0.setAttribute('offset', '50%');
|
|
100945
|
-
elStop1.setAttribute('offset', '100%');
|
|
100946
|
-
|
|
100947
|
-
elStop0.classList.add('color-stop-0');
|
|
100948
|
-
elStop1.classList.add('color-stop-1');
|
|
100891
|
+
* @param {number} subject_v0
|
|
100892
|
+
* @param {number} subject_v1
|
|
100893
|
+
* @param {number} bounds_v0
|
|
100894
|
+
* @param {number} bounds_v1
|
|
100895
|
+
* @returns {number} displacement for subject to fit into bounds
|
|
100896
|
+
*/
|
|
100897
|
+
function interval_force_into_bounds(
|
|
100898
|
+
subject_v0, subject_v1,
|
|
100899
|
+
bounds_v0, bounds_v1
|
|
100900
|
+
){
|
|
100949
100901
|
|
|
100950
|
-
|
|
100951
|
-
elGradient.appendChild(elStop1);
|
|
100952
|
-
elSVG.appendChild(elDefs);
|
|
100902
|
+
let displacement = 0;
|
|
100953
100903
|
|
|
100954
|
-
|
|
100955
|
-
const w = 24;
|
|
100904
|
+
const bounds_span = bounds_v1 - bounds_v0;
|
|
100956
100905
|
|
|
100957
|
-
|
|
100906
|
+
const subject_span = subject_v1 - subject_v0;
|
|
100958
100907
|
|
|
100959
|
-
|
|
100960
|
-
|
|
100908
|
+
if(bounds_span >= subject_span) {
|
|
100909
|
+
// fits
|
|
100961
100910
|
|
|
100962
|
-
|
|
100911
|
+
if (subject_v0 < bounds_v0) {
|
|
100912
|
+
displacement = bounds_v0 - subject_v0;
|
|
100913
|
+
} else if (subject_v1 > bounds_v1) {
|
|
100914
|
+
displacement = bounds_v1 - subject_v1;
|
|
100915
|
+
}
|
|
100963
100916
|
|
|
100964
|
-
|
|
100965
|
-
|
|
100966
|
-
elPolygon.classList.add('compass-triangle');
|
|
100917
|
+
}else {
|
|
100918
|
+
// too big to fit, pick the smallest displacement to occupy entire bounds
|
|
100967
100919
|
|
|
100968
|
-
|
|
100920
|
+
const a = subject_v0 - bounds_v0;
|
|
100921
|
+
const b = bounds_v1 - subject_v1;
|
|
100969
100922
|
|
|
100970
|
-
|
|
100971
|
-
|
|
100923
|
+
if(a > 0 && a < b){
|
|
100924
|
+
displacement = -a;
|
|
100925
|
+
}else if(b > 0){
|
|
100926
|
+
displacement = b;
|
|
100927
|
+
}
|
|
100928
|
+
}
|
|
100972
100929
|
|
|
100973
|
-
|
|
100974
|
-
|
|
100975
|
-
elSVG.style.left = `-${t}px`;
|
|
100930
|
+
return displacement;
|
|
100931
|
+
}
|
|
100976
100932
|
|
|
100977
|
-
|
|
100978
|
-
|
|
100933
|
+
/**
|
|
100934
|
+
*
|
|
100935
|
+
* @param {AABB2} container
|
|
100936
|
+
* @param {AABB2} box
|
|
100937
|
+
*/
|
|
100938
|
+
function aabb2_force_into_container(container, box) {
|
|
100979
100939
|
|
|
100980
|
-
|
|
100981
|
-
|
|
100940
|
+
const dX = interval_force_into_bounds(box.x0, box.x1, container.x0, container.x1);
|
|
100941
|
+
const dY = interval_force_into_bounds(box.y0, box.y1, container.y0, container.y1);
|
|
100982
100942
|
|
|
100983
|
-
|
|
100984
|
-
}
|
|
100943
|
+
box.move(dX, dY);
|
|
100985
100944
|
}
|
|
100986
100945
|
|
|
100987
100946
|
/**
|
|
100988
100947
|
* Note: assumes that boxes to be contained are strictly smaller than the container in both dimensions
|
|
100989
100948
|
* @param {AABB2} container
|
|
100990
|
-
* @param {Array.<AABB2>} boxes
|
|
100949
|
+
* @param {Array.<AABB2|{locked?:boolean}>} boxes
|
|
100991
100950
|
*/
|
|
100992
100951
|
function forceIntoBox(container, boxes) {
|
|
100993
100952
|
for (let i = 0, l = boxes.length; i < l; i++) {
|
|
@@ -100997,34 +100956,8 @@ function forceIntoBox(container, boxes) {
|
|
|
100997
100956
|
continue;
|
|
100998
100957
|
}
|
|
100999
100958
|
|
|
101000
|
-
|
|
101001
|
-
let dY = 0;
|
|
100959
|
+
aabb2_force_into_container(container, box);
|
|
101002
100960
|
|
|
101003
|
-
const bx0 = box.x0;
|
|
101004
|
-
const bx1 = box.x1;
|
|
101005
|
-
|
|
101006
|
-
const by0 = box.y0;
|
|
101007
|
-
const by1 = box.y1;
|
|
101008
|
-
|
|
101009
|
-
const cx0 = container.x0;
|
|
101010
|
-
const cx1 = container.x1;
|
|
101011
|
-
|
|
101012
|
-
const cy0 = container.y0;
|
|
101013
|
-
const cy1 = container.y1;
|
|
101014
|
-
|
|
101015
|
-
if (bx0 < cx0) {
|
|
101016
|
-
dX = cx0 - bx0;
|
|
101017
|
-
} else if (bx1 > cx1) {
|
|
101018
|
-
dX = cx1 - bx1;
|
|
101019
|
-
}
|
|
101020
|
-
|
|
101021
|
-
if (by0 < cy0) {
|
|
101022
|
-
dY = cy0 - by0;
|
|
101023
|
-
} else if (by1 > cy1) {
|
|
101024
|
-
dY = cy1 - by1;
|
|
101025
|
-
}
|
|
101026
|
-
|
|
101027
|
-
box.move(dX, dY);
|
|
101028
100961
|
}
|
|
101029
100962
|
}
|
|
101030
100963
|
|
|
@@ -101035,9 +100968,14 @@ function forceIntoBox(container, boxes) {
|
|
|
101035
100968
|
* @param {number} targetY target point Y coordinate
|
|
101036
100969
|
* @param {number} strength
|
|
101037
100970
|
*/
|
|
101038
|
-
function pullBoxTowardsPoint(
|
|
101039
|
-
|
|
101040
|
-
|
|
100971
|
+
function pullBoxTowardsPoint(
|
|
100972
|
+
box,
|
|
100973
|
+
targetX, targetY,
|
|
100974
|
+
strength
|
|
100975
|
+
) {
|
|
100976
|
+
|
|
100977
|
+
const midX = box.centerX;
|
|
100978
|
+
const midY = box.centerY;
|
|
101041
100979
|
|
|
101042
100980
|
const deltaX = targetX - midX;
|
|
101043
100981
|
const deltaY = targetY - midY;
|
|
@@ -101053,6 +100991,7 @@ function pullBoxTowardsPoint(box, targetX, targetY, strength) {
|
|
|
101053
100991
|
*
|
|
101054
100992
|
* @param {Vector2[]} forces
|
|
101055
100993
|
* @param {Array.<AABB2>} boxes
|
|
100994
|
+
* @returns {number}
|
|
101056
100995
|
*/
|
|
101057
100996
|
function resolveBoxOverlapUsingForce(forces, boxes) {
|
|
101058
100997
|
const numBoxes = boxes.length;
|
|
@@ -101150,113 +101089,363 @@ function resolveBoxOverlapUsingForce(forces, boxes) {
|
|
|
101150
101089
|
/**
|
|
101151
101090
|
*
|
|
101152
101091
|
* @param {AABB2[]} boxes
|
|
101153
|
-
* @param {number} maxSteps
|
|
101092
|
+
* @param {number} [maxSteps]
|
|
101154
101093
|
*/
|
|
101155
|
-
function resolveAABB2Overlap(boxes, maxSteps) {
|
|
101094
|
+
function resolveAABB2Overlap(boxes, maxSteps=3) {
|
|
101156
101095
|
const forces = [];
|
|
101157
101096
|
|
|
101158
101097
|
const n = boxes.length;
|
|
101098
|
+
|
|
101159
101099
|
for (let i = 0; i < n; i++) {
|
|
101160
101100
|
forces.push(new Vector2(0, 0));
|
|
101161
101101
|
}
|
|
101162
101102
|
|
|
101163
101103
|
let overlapMoves = -1;
|
|
101164
|
-
|
|
101165
|
-
|
|
101104
|
+
|
|
101105
|
+
let steps = maxSteps;
|
|
101106
|
+
|
|
101107
|
+
while (steps > 0 && overlapMoves !== 0) {
|
|
101108
|
+
|
|
101109
|
+
steps--;
|
|
101110
|
+
|
|
101166
101111
|
overlapMoves = resolveBoxOverlapUsingForce(forces, boxes);
|
|
101112
|
+
|
|
101167
101113
|
}
|
|
101114
|
+
|
|
101168
101115
|
}
|
|
101169
101116
|
|
|
101170
|
-
|
|
101117
|
+
/**
|
|
101118
|
+
*
|
|
101119
|
+
* @param {AABB2} box
|
|
101120
|
+
* @param {AABB2} target
|
|
101121
|
+
* @param {AABB2} bounds
|
|
101122
|
+
* @returns {Vector2}
|
|
101123
|
+
*/
|
|
101124
|
+
function computeInitialPlacement(box, target, bounds) {
|
|
101171
101125
|
/**
|
|
101172
|
-
*
|
|
101173
|
-
* @
|
|
101174
|
-
* @param {View} contentView
|
|
101175
|
-
* @constructor
|
|
101126
|
+
* list of preferred directions, ordered. First direction is higher priority than the next, last is lowest priority
|
|
101127
|
+
* @type {Vector2[]}
|
|
101176
101128
|
*/
|
|
101177
|
-
|
|
101178
|
-
|
|
101129
|
+
const preferredDirections = [
|
|
101130
|
+
Vector2.up,
|
|
101131
|
+
Vector2.right,
|
|
101132
|
+
Vector2.down,
|
|
101133
|
+
Vector2.left
|
|
101134
|
+
];
|
|
101179
101135
|
|
|
101136
|
+
const targetCenter = target.getCenter();
|
|
101180
101137
|
|
|
101181
|
-
|
|
101182
|
-
|
|
101183
|
-
* @type {VisualTip}
|
|
101184
|
-
*/
|
|
101185
|
-
this.model = tip;
|
|
101138
|
+
const targetH = target.getHeight();
|
|
101139
|
+
const targetW = target.getWidth();
|
|
101186
101140
|
|
|
101187
|
-
|
|
101188
|
-
this.el = document.createElement('div');
|
|
101189
|
-
this.addClass("tooltip-view");
|
|
101141
|
+
const targetDiagonal = Math.sqrt(targetH * targetH + targetW * targetW);
|
|
101190
101142
|
|
|
101191
|
-
|
|
101143
|
+
const boxWidth = box.getWidth();
|
|
101144
|
+
const boxHeight = box.getHeight();
|
|
101192
101145
|
|
|
101193
|
-
|
|
101146
|
+
const boxWidth_2 = boxWidth / 2;
|
|
101147
|
+
const boxHeight_2 = boxHeight / 2;
|
|
101194
101148
|
|
|
101195
|
-
|
|
101149
|
+
const intersectionPoint = new Vector2();
|
|
101196
101150
|
|
|
101197
|
-
|
|
101151
|
+
const placements = preferredDirections.map(function (direction) {
|
|
101152
|
+
//invert Y axis, screen-space direction is Down(+) and Up(-)
|
|
101153
|
+
const viewportDirection = direction.clone()._multiply(1, -1);
|
|
101198
101154
|
|
|
101155
|
+
const pointOutside = viewportDirection.clone();
|
|
101156
|
+
//scale vector to be larger than the box diagonal so it would intersect the boundary when placed in the middle
|
|
101157
|
+
pointOutside.multiplyScalar(targetDiagonal + 1);
|
|
101158
|
+
//move vector to the middle od the box
|
|
101159
|
+
pointOutside.add(targetCenter);
|
|
101199
101160
|
|
|
101200
|
-
|
|
101161
|
+
target.lineIntersectionPoint(targetCenter, pointOutside, intersectionPoint);
|
|
101201
101162
|
|
|
101202
|
-
|
|
101163
|
+
//align placement to the opposite edge of the box
|
|
101164
|
+
const offset = new Vector2(boxWidth_2, boxHeight_2);
|
|
101203
101165
|
|
|
101204
|
-
|
|
101205
|
-
|
|
101166
|
+
offset.multiply(viewportDirection);
|
|
101167
|
+
|
|
101168
|
+
offset._sub(boxWidth_2, boxHeight_2);
|
|
101169
|
+
|
|
101170
|
+
offset.add(intersectionPoint);
|
|
101171
|
+
|
|
101172
|
+
return offset;
|
|
101173
|
+
});
|
|
101206
101174
|
|
|
101207
101175
|
/**
|
|
101208
101176
|
*
|
|
101209
|
-
* @param {
|
|
101177
|
+
* @param {Vector2} placement
|
|
101178
|
+
* @returns {number}
|
|
101210
101179
|
*/
|
|
101211
|
-
|
|
101212
|
-
|
|
101180
|
+
function computePlacementScore(placement) {
|
|
101181
|
+
//find space for the tip between bounds and the target
|
|
101182
|
+
const availableSpace = new AABB2();
|
|
101213
101183
|
|
|
101214
|
-
const
|
|
101184
|
+
const px0 = placement.x;
|
|
101185
|
+
const px1 = px0 + boxWidth;
|
|
101186
|
+
const py0 = placement.y;
|
|
101187
|
+
const py1 = py0 + boxHeight;
|
|
101215
101188
|
|
|
101216
|
-
|
|
101189
|
+
if (px1 <= target.x0) {
|
|
101190
|
+
//left
|
|
101191
|
+
availableSpace.set(
|
|
101192
|
+
bounds.x0,
|
|
101193
|
+
bounds.y0,
|
|
101194
|
+
target.x0,
|
|
101195
|
+
bounds.y1
|
|
101196
|
+
);
|
|
101197
|
+
} else if (px0 >= target.x1) {
|
|
101198
|
+
//right
|
|
101199
|
+
availableSpace.set(
|
|
101200
|
+
target.x1,
|
|
101201
|
+
bounds.y0,
|
|
101202
|
+
bounds.x1,
|
|
101203
|
+
bounds.y1
|
|
101204
|
+
);
|
|
101205
|
+
} else if (py1 <= target.y0) {
|
|
101206
|
+
//up
|
|
101207
|
+
availableSpace.set(
|
|
101208
|
+
bounds.x0,
|
|
101209
|
+
bounds.y0,
|
|
101210
|
+
bounds.x1,
|
|
101211
|
+
target.y0
|
|
101212
|
+
);
|
|
101213
|
+
} else if (py0 >= target.y1) {
|
|
101214
|
+
//bottom
|
|
101215
|
+
availableSpace.set(
|
|
101216
|
+
bounds.x0,
|
|
101217
|
+
target.y1,
|
|
101218
|
+
bounds.x1,
|
|
101219
|
+
bounds.y1
|
|
101220
|
+
);
|
|
101221
|
+
} else ;
|
|
101217
101222
|
|
|
101218
|
-
|
|
101219
|
-
*
|
|
101220
|
-
* @type {VisualTip}
|
|
101221
|
-
*/
|
|
101222
|
-
const tip = this.model;
|
|
101223
|
+
let score = 0;
|
|
101223
101224
|
|
|
101224
|
-
const
|
|
101225
|
+
const availableWidth = availableSpace.getWidth();
|
|
101226
|
+
const availableHeight = availableSpace.getHeight();
|
|
101225
101227
|
|
|
101226
|
-
const
|
|
101228
|
+
const spareWidth = availableWidth - boxWidth;
|
|
101229
|
+
const spareHeight = availableHeight - boxHeight;
|
|
101227
101230
|
|
|
101228
|
-
|
|
101231
|
+
if (spareHeight < 0) {
|
|
101232
|
+
score--;
|
|
101233
|
+
}
|
|
101229
101234
|
|
|
101230
|
-
|
|
101235
|
+
if (spareWidth < 0) {
|
|
101236
|
+
score--;
|
|
101237
|
+
}
|
|
101231
101238
|
|
|
101232
|
-
|
|
101239
|
+
return score;
|
|
101240
|
+
}
|
|
101233
101241
|
|
|
101234
|
-
|
|
101242
|
+
//score placements
|
|
101243
|
+
const scores = placements.map(computePlacementScore);
|
|
101235
101244
|
|
|
101236
|
-
|
|
101245
|
+
//find best placement
|
|
101246
|
+
let bestIndex = 0;
|
|
101247
|
+
let bestScore = scores[0];
|
|
101237
101248
|
|
|
101238
|
-
|
|
101249
|
+
for (let i = 1; i < scores.length; i++) {
|
|
101250
|
+
const score = scores[i];
|
|
101239
101251
|
|
|
101240
|
-
|
|
101252
|
+
if (score > bestScore + EPSILON) {
|
|
101253
|
+
bestScore = score;
|
|
101254
|
+
bestIndex = i;
|
|
101255
|
+
}
|
|
101256
|
+
}
|
|
101241
101257
|
|
|
101242
|
-
|
|
101258
|
+
return placements[bestIndex];
|
|
101259
|
+
}
|
|
101243
101260
|
|
|
101244
|
-
|
|
101245
|
-
|
|
101261
|
+
/**
|
|
101262
|
+
*
|
|
101263
|
+
* @param {AABB2} box
|
|
101264
|
+
* @param {AABB2} target
|
|
101265
|
+
* @param {AABB2} bounds
|
|
101266
|
+
* @returns {AABB2} input {@link box} parameter
|
|
101267
|
+
*/
|
|
101268
|
+
function position_box_next_to_box(box, target, bounds) {
|
|
101269
|
+
const b = box.clone();
|
|
101270
|
+
const t = target.clone();
|
|
101246
101271
|
|
|
101247
|
-
|
|
101272
|
+
//center box inside the bounds
|
|
101273
|
+
const y0 = (bounds.height + b.height) / 2;
|
|
101274
|
+
const x0 = (bounds.width + b.width) / 2;
|
|
101248
101275
|
|
|
101249
|
-
|
|
101276
|
+
b.set(x0, y0, x0 + b.width, y0 + b.height);
|
|
101277
|
+
|
|
101278
|
+
new Vector2(t.centerX, t.centerY);
|
|
101279
|
+
|
|
101280
|
+
t.locked = true;
|
|
101281
|
+
|
|
101282
|
+
|
|
101283
|
+
const initialPosition = computeInitialPlacement(b, t, bounds);
|
|
101284
|
+
//set bounds to initial position
|
|
101285
|
+
b.set(initialPosition.x, initialPosition.y, initialPosition.x + b.width, initialPosition.y + b.height);
|
|
101286
|
+
|
|
101287
|
+
// touch();
|
|
101288
|
+
|
|
101289
|
+
function step() {
|
|
101290
|
+
//pull
|
|
101291
|
+
pullBoxTowardsPoint(b, initialPosition.x + b.width / 2, initialPosition.y + b.height / 2, 0.1);
|
|
101292
|
+
|
|
101293
|
+
resolveAABB2Overlap([b, t], 10);
|
|
101294
|
+
|
|
101295
|
+
forceIntoBox(bounds, [b]);
|
|
101296
|
+
}
|
|
101297
|
+
|
|
101298
|
+
for (let i = 0; i < 5; i++) {
|
|
101299
|
+
step();
|
|
101250
101300
|
}
|
|
101301
|
+
|
|
101302
|
+
box.copy(b);
|
|
101303
|
+
|
|
101304
|
+
return box;
|
|
101305
|
+
}
|
|
101306
|
+
|
|
101307
|
+
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
101308
|
+
|
|
101309
|
+
/**
|
|
101310
|
+
*
|
|
101311
|
+
* @param {number} r0 inner radius
|
|
101312
|
+
* @param {number} r1 outer radius
|
|
101313
|
+
* @param {number} a0 starting angle
|
|
101314
|
+
* @param {number} a1 end angle
|
|
101315
|
+
* @returns {string}
|
|
101316
|
+
*/
|
|
101317
|
+
function svgArc(r0, r1, a0, a1) {
|
|
101318
|
+
let da, df;
|
|
101319
|
+
const c0 = Math.cos(a0);
|
|
101320
|
+
const s0 = Math.sin(a0);
|
|
101321
|
+
const c1 = Math.cos(a1);
|
|
101322
|
+
const s1 = Math.sin(a1);
|
|
101323
|
+
|
|
101324
|
+
da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0);
|
|
101325
|
+
|
|
101326
|
+
df = da < Math.PI ? "0" : "1";
|
|
101327
|
+
|
|
101328
|
+
return "M" + r1 * c0 + "," + r1 * s0
|
|
101329
|
+
+ "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1
|
|
101330
|
+
+ "L" + r0 * c1 + "," + r0 * s1
|
|
101331
|
+
+ "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0
|
|
101332
|
+
+ "Z";
|
|
101333
|
+
}
|
|
101334
|
+
|
|
101335
|
+
/**
|
|
101336
|
+
*
|
|
101337
|
+
* @param {number} r0 Inner radius
|
|
101338
|
+
* @param {number} r1 Outer Radius
|
|
101339
|
+
* @param {number} a0 Start of the inner arc (in rad)
|
|
101340
|
+
* @param {number} b0 End of the inner arc (in rad)
|
|
101341
|
+
* @param {number} a1 Start of the outer arc (in rad)
|
|
101342
|
+
* @param {number} b1 End of the outer arc (in rad)
|
|
101343
|
+
* @returns {string}
|
|
101344
|
+
*/
|
|
101345
|
+
function svgArc2(r0, r1, a0, b0, a1, b1) {
|
|
101346
|
+
const ac0 = Math.cos(a0);
|
|
101347
|
+
const as0 = Math.sin(a0);
|
|
101348
|
+
|
|
101349
|
+
const bc0 = Math.cos(b0);
|
|
101350
|
+
const bs0 = Math.sin(b0);
|
|
101351
|
+
|
|
101352
|
+
const ac1 = Math.cos(a1);
|
|
101353
|
+
const as1 = Math.sin(a1);
|
|
101354
|
+
|
|
101355
|
+
const bc1 = Math.cos(b1);
|
|
101356
|
+
const bs1 = Math.sin(b1);
|
|
101357
|
+
|
|
101358
|
+
const largeArcFlag0 = b0 - a0 <= Math.PI ? "0" : "1";
|
|
101359
|
+
const largeArcFlag1 = b1 - a1 <= Math.PI ? "0" : "1";
|
|
101360
|
+
|
|
101361
|
+
return `
|
|
101362
|
+
M${r1 * ac1},${r1 * as1}
|
|
101363
|
+
A${r1},${r1} 0 ${largeArcFlag1},1 ${r1 * bc1},${r1 * bs1}
|
|
101364
|
+
L${r0 * bc0},${r0 * bs0}
|
|
101365
|
+
A${r0},${r0} 0 ${largeArcFlag0},0 ${r0 * ac0},${r0 * as0}
|
|
101366
|
+
Z
|
|
101367
|
+
`;
|
|
101368
|
+
}
|
|
101369
|
+
|
|
101370
|
+
/**
|
|
101371
|
+
*
|
|
101372
|
+
* @param {String} tag
|
|
101373
|
+
* @returns {Element}
|
|
101374
|
+
*/
|
|
101375
|
+
function createSVGElement(tag) {
|
|
101376
|
+
return document.createElementNS(SVG_NAMESPACE, tag);
|
|
101251
101377
|
}
|
|
101252
101378
|
|
|
101379
|
+
var SVG = {
|
|
101380
|
+
arcPath: svgArc,
|
|
101381
|
+
svgArc2,
|
|
101382
|
+
createElement: createSVGElement
|
|
101383
|
+
};
|
|
101384
|
+
|
|
101385
|
+
class CompassArrowView extends View {
|
|
101386
|
+
constructor() {
|
|
101387
|
+
super();
|
|
101388
|
+
|
|
101389
|
+
|
|
101390
|
+
const elSVG = SVG.createElement('svg');
|
|
101391
|
+
|
|
101392
|
+
const elDefs = SVG.createElement('defs');
|
|
101393
|
+
const elGradient = SVG.createElement('linearGradient');
|
|
101394
|
+
elGradient.setAttribute('id', 'gradient');
|
|
101395
|
+
|
|
101396
|
+
elDefs.appendChild(elGradient);
|
|
101397
|
+
const elStop0 = SVG.createElement('stop');
|
|
101398
|
+
const elStop1 = SVG.createElement('stop');
|
|
101399
|
+
|
|
101400
|
+
elStop0.setAttribute('offset', '50%');
|
|
101401
|
+
elStop1.setAttribute('offset', '100%');
|
|
101402
|
+
|
|
101403
|
+
elStop0.classList.add('color-stop-0');
|
|
101404
|
+
elStop1.classList.add('color-stop-1');
|
|
101405
|
+
|
|
101406
|
+
elGradient.appendChild(elStop0);
|
|
101407
|
+
elGradient.appendChild(elStop1);
|
|
101408
|
+
elSVG.appendChild(elDefs);
|
|
101409
|
+
|
|
101410
|
+
const h = 28;
|
|
101411
|
+
const w = 24;
|
|
101412
|
+
|
|
101413
|
+
elSVG.classList.add('compass');
|
|
101414
|
+
|
|
101415
|
+
elSVG.setAttribute('width', h);
|
|
101416
|
+
elSVG.setAttribute('height', w);
|
|
101417
|
+
|
|
101418
|
+
const elPolygon = SVG.createElement('polygon');
|
|
101419
|
+
|
|
101420
|
+
const half_w = w / 2;
|
|
101421
|
+
elPolygon.setAttribute('points', `${h},${half_w} 0,${w} 0,0`);
|
|
101422
|
+
elPolygon.classList.add('compass-triangle');
|
|
101423
|
+
|
|
101424
|
+
elSVG.appendChild(elPolygon);
|
|
101425
|
+
|
|
101426
|
+
//set rotation origin to the bottom middle of the element
|
|
101427
|
+
const t = half_w * Math.SQRT2;
|
|
101253
101428
|
|
|
101429
|
+
elSVG.style.transformOrigin = `${t}px ${half_w}px`;
|
|
101430
|
+
elSVG.style.top = `-${half_w}px`;
|
|
101431
|
+
elSVG.style.left = `-${t}px`;
|
|
101432
|
+
|
|
101433
|
+
this.el = elSVG;
|
|
101434
|
+
}
|
|
101435
|
+
|
|
101436
|
+
rotateFromDirectionVector(x, y) {
|
|
101437
|
+
const angle = Math.atan2(y, x);
|
|
101438
|
+
|
|
101439
|
+
this.rotation.set(angle);
|
|
101440
|
+
}
|
|
101441
|
+
}
|
|
101442
|
+
|
|
101254
101443
|
/**
|
|
101255
101444
|
*
|
|
101256
101445
|
* @param {Element} el
|
|
101257
101446
|
* @returns {AABB2}
|
|
101258
101447
|
*/
|
|
101259
|
-
function
|
|
101448
|
+
function html_element_to_aabb(el) {
|
|
101260
101449
|
const clientRect = el.getBoundingClientRect();
|
|
101261
101450
|
|
|
101262
101451
|
let x0 = clientRect.left;
|
|
@@ -101277,224 +101466,89 @@ function element2aabb(el) {
|
|
|
101277
101466
|
// write bounds
|
|
101278
101467
|
|
|
101279
101468
|
return new AABB2(x0, y0, x1, y1);
|
|
101280
|
-
}
|
|
101281
|
-
|
|
101282
|
-
|
|
101283
|
-
*
|
|
101284
|
-
* @param {Rectangle} rect
|
|
101285
|
-
* @returns {AABB2}
|
|
101286
|
-
*/
|
|
101287
|
-
function rectangle2aabb(rect) {
|
|
101288
|
-
const position = rect.position;
|
|
101289
|
-
|
|
101290
|
-
const x0 = position.x;
|
|
101291
|
-
const y0 = position.y;
|
|
101292
|
-
|
|
101293
|
-
const size = rect.size;
|
|
101294
|
-
|
|
101295
|
-
let x1 = x0;
|
|
101296
|
-
let y1 = y0;
|
|
101297
|
-
|
|
101298
|
-
// sanitize bounds
|
|
101299
|
-
if (size.x > 0) {
|
|
101300
|
-
x1 += size.x;
|
|
101301
|
-
}
|
|
101302
|
-
|
|
101303
|
-
if (size.y > 0) {
|
|
101304
|
-
y1 += size.y;
|
|
101305
|
-
}
|
|
101306
|
-
|
|
101307
|
-
return new AABB2(x0, y0, x1, y1);
|
|
101308
|
-
}
|
|
101309
|
-
|
|
101310
|
-
/**
|
|
101311
|
-
*
|
|
101312
|
-
* @param {AABB2} box
|
|
101313
|
-
* @param {AABB2} target
|
|
101314
|
-
* @param {AABB2} bounds
|
|
101315
|
-
* @returns {Vector2}
|
|
101316
|
-
*/
|
|
101317
|
-
function computeInitialPlacement(box, target, bounds) {
|
|
101469
|
+
}
|
|
101470
|
+
|
|
101471
|
+
class TooltipView extends View {
|
|
101318
101472
|
/**
|
|
101319
|
-
*
|
|
101320
|
-
* @
|
|
101473
|
+
*
|
|
101474
|
+
* @param {VisualTip} tip
|
|
101475
|
+
* @param {View} contentView
|
|
101476
|
+
* @constructor
|
|
101321
101477
|
*/
|
|
101322
|
-
|
|
101323
|
-
|
|
101324
|
-
Vector2.right,
|
|
101325
|
-
Vector2.down,
|
|
101326
|
-
Vector2.left
|
|
101327
|
-
];
|
|
101328
|
-
|
|
101329
|
-
const targetCenter = new Vector2(target.midX(), target.midY());
|
|
101330
|
-
|
|
101331
|
-
const targetH = target.getHeight();
|
|
101332
|
-
const targetW = target.getWidth();
|
|
101333
|
-
|
|
101334
|
-
const targetDiagonal = Math.sqrt(targetH * targetH + targetW * targetW);
|
|
101478
|
+
constructor(tip, contentView) {
|
|
101479
|
+
super();
|
|
101335
101480
|
|
|
101336
|
-
const boxWidth = box.getWidth();
|
|
101337
|
-
const boxHeight = box.getHeight();
|
|
101338
101481
|
|
|
101339
|
-
|
|
101340
|
-
|
|
101482
|
+
/**
|
|
101483
|
+
*
|
|
101484
|
+
* @type {VisualTip}
|
|
101485
|
+
*/
|
|
101486
|
+
this.model = tip;
|
|
101341
101487
|
|
|
101342
|
-
|
|
101488
|
+
//set dom element
|
|
101489
|
+
this.el = document.createElement('div');
|
|
101490
|
+
this.addClass("tooltip-view");
|
|
101343
101491
|
|
|
101344
|
-
|
|
101345
|
-
//invert Y axis, screen-space direction is Down(+) and Up(-)
|
|
101346
|
-
const viewportDirection = direction.clone()._multiply(1, -1);
|
|
101492
|
+
const vContents = new EmptyView({ classList: ['contents'] });
|
|
101347
101493
|
|
|
101348
|
-
|
|
101349
|
-
//scale vector to be larger than the box diagonal so it would intersect the boundary when placed in the middle
|
|
101350
|
-
pointOutside.multiplyScalar(targetDiagonal + 1);
|
|
101351
|
-
//move vector to the middle od the box
|
|
101352
|
-
pointOutside.add(targetCenter);
|
|
101494
|
+
this.addChild(vContents);
|
|
101353
101495
|
|
|
101354
|
-
|
|
101496
|
+
vContents.addChild(contentView);
|
|
101355
101497
|
|
|
101356
|
-
|
|
101357
|
-
const offset = new Vector2(boxWidth_2, boxHeight_2);
|
|
101498
|
+
this.contentView = vContents;
|
|
101358
101499
|
|
|
101359
|
-
offset.multiply(viewportDirection);
|
|
101360
101500
|
|
|
101361
|
-
|
|
101501
|
+
const vCompass = new CompassArrowView();
|
|
101362
101502
|
|
|
101363
|
-
|
|
101503
|
+
this.addChild(vCompass);
|
|
101364
101504
|
|
|
101365
|
-
|
|
101366
|
-
}
|
|
101505
|
+
this.compass = vCompass;
|
|
101506
|
+
}
|
|
101367
101507
|
|
|
101368
101508
|
/**
|
|
101369
101509
|
*
|
|
101370
|
-
* @param {
|
|
101371
|
-
* @returns {number}
|
|
101510
|
+
* @param {AABB2} bounds
|
|
101372
101511
|
*/
|
|
101373
|
-
|
|
101374
|
-
|
|
101375
|
-
const availableSpace = new AABB2();
|
|
101376
|
-
|
|
101377
|
-
const px0 = placement.x;
|
|
101378
|
-
const px1 = px0 + boxWidth;
|
|
101379
|
-
const py0 = placement.y;
|
|
101380
|
-
const py1 = py0 + boxHeight;
|
|
101381
|
-
|
|
101382
|
-
if (px1 <= target.x0) {
|
|
101383
|
-
//left
|
|
101384
|
-
availableSpace.set(
|
|
101385
|
-
bounds.x0,
|
|
101386
|
-
bounds.y0,
|
|
101387
|
-
target.x0,
|
|
101388
|
-
bounds.y1
|
|
101389
|
-
);
|
|
101390
|
-
} else if (px0 >= target.x1) {
|
|
101391
|
-
//right
|
|
101392
|
-
availableSpace.set(
|
|
101393
|
-
target.x1,
|
|
101394
|
-
bounds.y0,
|
|
101395
|
-
bounds.x1,
|
|
101396
|
-
bounds.y1
|
|
101397
|
-
);
|
|
101398
|
-
} else if (py1 <= target.y0) {
|
|
101399
|
-
//up
|
|
101400
|
-
availableSpace.set(
|
|
101401
|
-
bounds.x0,
|
|
101402
|
-
bounds.y0,
|
|
101403
|
-
bounds.x1,
|
|
101404
|
-
target.y0
|
|
101405
|
-
);
|
|
101406
|
-
} else if (py0 >= target.y1) {
|
|
101407
|
-
//bottom
|
|
101408
|
-
availableSpace.set(
|
|
101409
|
-
bounds.x0,
|
|
101410
|
-
target.y1,
|
|
101411
|
-
bounds.x1,
|
|
101412
|
-
bounds.y1
|
|
101413
|
-
);
|
|
101414
|
-
} else ;
|
|
101415
|
-
|
|
101416
|
-
let score = 0;
|
|
101417
|
-
|
|
101418
|
-
const availableWidth = availableSpace.getWidth();
|
|
101419
|
-
const availableHeight = availableSpace.getHeight();
|
|
101420
|
-
|
|
101421
|
-
const spareWidth = availableWidth - boxWidth;
|
|
101422
|
-
const spareHeight = availableHeight - boxHeight;
|
|
101423
|
-
|
|
101424
|
-
if (spareHeight < 0) {
|
|
101425
|
-
score--;
|
|
101426
|
-
}
|
|
101427
|
-
|
|
101428
|
-
if (spareWidth < 0) {
|
|
101429
|
-
score--;
|
|
101430
|
-
}
|
|
101431
|
-
|
|
101432
|
-
return score;
|
|
101433
|
-
}
|
|
101434
|
-
|
|
101435
|
-
//score placements
|
|
101436
|
-
const scores = placements.map(computePlacementScore);
|
|
101512
|
+
layout(bounds) {
|
|
101513
|
+
const tipBox = html_element_to_aabb(this.contentView.el);
|
|
101437
101514
|
|
|
101438
|
-
|
|
101439
|
-
let bestIndex = 0;
|
|
101440
|
-
let bestScore = scores[0];
|
|
101515
|
+
const SPACING = 16;
|
|
101441
101516
|
|
|
101442
|
-
|
|
101443
|
-
const score = scores[i];
|
|
101517
|
+
tipBox.grow(SPACING);
|
|
101444
101518
|
|
|
101445
|
-
|
|
101446
|
-
|
|
101447
|
-
|
|
101448
|
-
|
|
101449
|
-
|
|
101519
|
+
/**
|
|
101520
|
+
*
|
|
101521
|
+
* @type {VisualTip}
|
|
101522
|
+
*/
|
|
101523
|
+
const tip = this.model;
|
|
101450
101524
|
|
|
101451
|
-
|
|
101452
|
-
}
|
|
101525
|
+
const tipTarget = tip.target;
|
|
101453
101526
|
|
|
101527
|
+
const target = rectangle_to_aabb(tipTarget);
|
|
101454
101528
|
|
|
101455
|
-
|
|
101456
|
-
*
|
|
101457
|
-
* @param {AABB2} box
|
|
101458
|
-
* @param {AABB2} target
|
|
101459
|
-
* @param {AABB2} bounds
|
|
101460
|
-
*/
|
|
101461
|
-
function positionBoxNextToBox(box, target, bounds) {
|
|
101462
|
-
const b = box.clone();
|
|
101463
|
-
const t = target.clone();
|
|
101464
|
-
|
|
101465
|
-
//center box inside the bounds
|
|
101466
|
-
const y0 = (bounds.getHeight() + b.getHeight()) / 2;
|
|
101467
|
-
const x0 = (bounds.getWidth() + b.getWidth()) / 2;
|
|
101468
|
-
b.set(x0, y0, x0 + b.getWidth(), y0 + b.getHeight());
|
|
101529
|
+
const box = position_box_next_to_box(tipBox, target, bounds);
|
|
101469
101530
|
|
|
101531
|
+
box.shrink(SPACING);
|
|
101470
101532
|
|
|
101471
|
-
|
|
101533
|
+
const compass = this.compass;
|
|
101472
101534
|
|
|
101473
|
-
|
|
101535
|
+
function setCompass() {
|
|
101474
101536
|
|
|
101537
|
+
const targetCenter = target.getCenter();
|
|
101475
101538
|
|
|
101476
|
-
|
|
101477
|
-
//set bounds to initial position
|
|
101478
|
-
b.set(initialPosition.x, initialPosition.y, initialPosition.x + b.getWidth(), initialPosition.y + b.getHeight());
|
|
101539
|
+
const tipPoint = new Vector2();
|
|
101479
101540
|
|
|
101480
|
-
|
|
101541
|
+
box.computeNearestPointToPoint(targetCenter, tipPoint);
|
|
101481
101542
|
|
|
101482
|
-
|
|
101483
|
-
//pull
|
|
101484
|
-
pullBoxTowardsPoint(b, initialPosition.x + b.getWidth() / 2, initialPosition.y + b.getHeight() / 2, 0.1);
|
|
101543
|
+
compass.rotateFromDirectionVector(targetCenter.x - tipPoint.x, targetCenter.y - tipPoint.y);
|
|
101485
101544
|
|
|
101486
|
-
|
|
101545
|
+
compass.position.copy(tipPoint)._add(-box.x0, -box.y0);
|
|
101546
|
+
}
|
|
101487
101547
|
|
|
101488
|
-
|
|
101489
|
-
}
|
|
101548
|
+
setCompass();
|
|
101490
101549
|
|
|
101491
|
-
|
|
101492
|
-
step();
|
|
101550
|
+
this.position.set(box.x0, box.y0);
|
|
101493
101551
|
}
|
|
101494
|
-
|
|
101495
|
-
box.copy(b);
|
|
101496
|
-
|
|
101497
|
-
return box;
|
|
101498
101552
|
}
|
|
101499
101553
|
|
|
101500
101554
|
class TooltipManager {
|
|
@@ -102822,40 +102876,37 @@ function playTrackRealTime(track, ecd) {
|
|
|
102822
102876
|
}
|
|
102823
102877
|
|
|
102824
102878
|
/**
|
|
102825
|
-
*
|
|
102826
|
-
* @
|
|
102827
|
-
* @
|
|
102828
|
-
* @param {
|
|
102829
|
-
* @param {
|
|
102830
|
-
* @param {
|
|
102831
|
-
* @
|
|
102879
|
+
* 3-rd (cubic) degree bezier curve
|
|
102880
|
+
* @see https://www.youtube.com/watch?v=jvPPXbo87ds&t=234s
|
|
102881
|
+
* @see https://en.wikipedia.org/wiki/B%C3%A9zier_curve
|
|
102882
|
+
* @param {number} t factor value between 0..1
|
|
102883
|
+
* @param {number} p0 start point
|
|
102884
|
+
* @param {number} p1 control point
|
|
102885
|
+
* @param {number} p2 control point
|
|
102886
|
+
* @param {number} p3 end point
|
|
102887
|
+
* @returns {number}
|
|
102832
102888
|
*/
|
|
102833
|
-
function
|
|
102834
|
-
|
|
102835
|
-
|
|
102836
|
-
* @type {number}
|
|
102837
|
-
*/
|
|
102838
|
-
const cX = 3 * (p1 - p0);
|
|
102889
|
+
function spline_bezier3(t, p0, p1, p2, p3) {
|
|
102890
|
+
// first we compute necessary factors for each point
|
|
102891
|
+
const nt = 1 - t;
|
|
102839
102892
|
|
|
102840
|
-
|
|
102841
|
-
*
|
|
102842
|
-
* @type {number}
|
|
102843
|
-
*/
|
|
102844
|
-
const bX = 3 * (p2 - p1) - cX;
|
|
102893
|
+
const nt_2 = nt * nt;
|
|
102845
102894
|
|
|
102846
|
-
|
|
102847
|
-
*
|
|
102848
|
-
* @type {number}
|
|
102849
|
-
*/
|
|
102850
|
-
const aX = p3 - p0 - cX - bX;
|
|
102895
|
+
const nt_3 = nt_2 * nt;
|
|
102851
102896
|
|
|
102852
102897
|
const t_2 = t * t;
|
|
102853
102898
|
|
|
102854
102899
|
const t_3 = t_2 * t;
|
|
102855
102900
|
|
|
102856
|
-
|
|
102901
|
+
// combine factors with point values to produce final result
|
|
102902
|
+
return nt_3 * p0 + 3 * nt_2 * t * p1 + 3 * nt * t_2 * p2 + t_3 * p3;
|
|
102857
102903
|
}
|
|
102858
102904
|
|
|
102905
|
+
/**
|
|
102906
|
+
* @deprecated use {@link spline_bezier3} directly
|
|
102907
|
+
*/
|
|
102908
|
+
const cubicCurve = spline_bezier3;
|
|
102909
|
+
|
|
102859
102910
|
/**
|
|
102860
102911
|
*
|
|
102861
102912
|
* @param {Number} p0
|
|
@@ -107371,28 +107422,18 @@ class ReferencedTextureAtlas extends AbstractTextureAtlas {
|
|
|
107371
107422
|
* @extends {AABB2}
|
|
107372
107423
|
*/
|
|
107373
107424
|
class QuadTreeDatum extends AABB2 {
|
|
107425
|
+
|
|
107374
107426
|
/**
|
|
107375
107427
|
*
|
|
107376
|
-
* @
|
|
107377
|
-
* @param {Number} [y0=0]
|
|
107378
|
-
* @param {Number} [x1=0]
|
|
107379
|
-
* @param {Number} [y1=0]
|
|
107428
|
+
* @type {D|null}
|
|
107380
107429
|
*/
|
|
107381
|
-
|
|
107382
|
-
super(x0, y0, x1, y1);
|
|
107383
|
-
|
|
107384
|
-
/**
|
|
107385
|
-
*
|
|
107386
|
-
* @type {D|null}
|
|
107387
|
-
*/
|
|
107388
|
-
this.data = null;
|
|
107430
|
+
data = null;
|
|
107389
107431
|
|
|
107390
|
-
|
|
107391
|
-
|
|
107392
|
-
|
|
107393
|
-
|
|
107394
|
-
|
|
107395
|
-
}
|
|
107432
|
+
/**
|
|
107433
|
+
*
|
|
107434
|
+
* @type {QuadTreeNode|null}
|
|
107435
|
+
*/
|
|
107436
|
+
parentNode = null;
|
|
107396
107437
|
|
|
107397
107438
|
disconnect() {
|
|
107398
107439
|
const parentNode = this.parentNode;
|