@equinor/esv-intersection 3.0.3 → 3.0.4

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 (109) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.mjs +1 -2
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/index.umd.js +1 -1
  6. package/dist/index.umd.js.map +1 -1
  7. package/package.json +11 -11
  8. package/dist/components/axis.d.ts +0 -47
  9. package/dist/components/index.d.ts +0 -1
  10. package/dist/control/ExtendedCurveInterpolator.d.ts +0 -58
  11. package/dist/control/IntersectionReferenceSystem.d.ts +0 -96
  12. package/dist/control/LayerManager.d.ts +0 -76
  13. package/dist/control/MainController.d.ts +0 -154
  14. package/dist/control/ZoomPanHandler.d.ts +0 -158
  15. package/dist/control/index.d.ts +0 -5
  16. package/dist/control/interfaces.d.ts +0 -37
  17. package/dist/control/overlay.d.ts +0 -20
  18. package/dist/datautils/colortable.d.ts +0 -1
  19. package/dist/datautils/findsample.d.ts +0 -2
  20. package/dist/datautils/index.d.ts +0 -6
  21. package/dist/datautils/interfaces.d.ts +0 -63
  22. package/dist/datautils/picks.d.ts +0 -74
  23. package/dist/datautils/schematicShapeGenerator.d.ts +0 -59
  24. package/dist/datautils/seismicimage.d.ts +0 -45
  25. package/dist/datautils/surfacedata.d.ts +0 -10
  26. package/dist/datautils/trajectory.d.ts +0 -14
  27. package/dist/layers/CalloutCanvasLayer.d.ts +0 -60
  28. package/dist/layers/CustomDisplayObjects/ComplexRope.d.ts +0 -22
  29. package/dist/layers/CustomDisplayObjects/ComplexRopeGeometry.d.ts +0 -27
  30. package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRope.d.ts +0 -20
  31. package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.d.ts +0 -26
  32. package/dist/layers/CustomDisplayObjects/UniformTextureStretchRope.d.ts +0 -17
  33. package/dist/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.d.ts +0 -24
  34. package/dist/layers/GeomodelCanvasLayer.d.ts +0 -28
  35. package/dist/layers/GeomodelLabelsLayer.d.ts +0 -49
  36. package/dist/layers/GeomodelLayerV2.d.ts +0 -12
  37. package/dist/layers/GridLayer.d.ts +0 -29
  38. package/dist/layers/ImageCanvasLayer.d.ts +0 -20
  39. package/dist/layers/ReferenceLineLayer.d.ts +0 -29
  40. package/dist/layers/SchematicLayer.d.ts +0 -113
  41. package/dist/layers/SeismicCanvasLayer.d.ts +0 -18
  42. package/dist/layers/WellborePathLayer.d.ts +0 -17
  43. package/dist/layers/base/CanvasLayer.d.ts +0 -19
  44. package/dist/layers/base/HTMLLayer.d.ts +0 -13
  45. package/dist/layers/base/Layer.d.ts +0 -69
  46. package/dist/layers/base/PixiLayer.d.ts +0 -32
  47. package/dist/layers/base/SVGLayer.d.ts +0 -13
  48. package/dist/layers/base/index.d.ts +0 -5
  49. package/dist/layers/index.d.ts +0 -16
  50. package/dist/layers/schematicInterfaces.d.ts +0 -209
  51. package/dist/utils/arc-length.d.ts +0 -23
  52. package/dist/utils/binary-search.d.ts +0 -8
  53. package/dist/utils/color.d.ts +0 -5
  54. package/dist/utils/index.d.ts +0 -1
  55. package/dist/utils/root-finder.d.ts +0 -34
  56. package/dist/utils/text.d.ts +0 -14
  57. package/dist/utils/vectorUtils.d.ts +0 -15
  58. package/dist/vendor/pixi-dashed-line/index.d.ts +0 -57
  59. package/src/components/axis.ts +0 -247
  60. package/src/components/index.ts +0 -1
  61. package/src/control/ExtendedCurveInterpolator.ts +0 -155
  62. package/src/control/IntersectionReferenceSystem.ts +0 -391
  63. package/src/control/LayerManager.ts +0 -294
  64. package/src/control/MainController.ts +0 -296
  65. package/src/control/ZoomPanHandler.ts +0 -436
  66. package/src/control/index.ts +0 -5
  67. package/src/control/interfaces.ts +0 -42
  68. package/src/control/overlay.ts +0 -118
  69. package/src/datautils/colortable.ts +0 -14
  70. package/src/datautils/findsample.ts +0 -64
  71. package/src/datautils/index.ts +0 -6
  72. package/src/datautils/interfaces.ts +0 -68
  73. package/src/datautils/picks.ts +0 -328
  74. package/src/datautils/schematicShapeGenerator.ts +0 -1008
  75. package/src/datautils/seismicimage.ts +0 -180
  76. package/src/datautils/surfacedata.ts +0 -318
  77. package/src/datautils/trajectory.ts +0 -206
  78. package/src/layers/CalloutCanvasLayer.ts +0 -338
  79. package/src/layers/CustomDisplayObjects/ComplexRope.ts +0 -45
  80. package/src/layers/CustomDisplayObjects/ComplexRopeGeometry.ts +0 -190
  81. package/src/layers/CustomDisplayObjects/FixedWidthSimpleRope.ts +0 -41
  82. package/src/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.ts +0 -149
  83. package/src/layers/CustomDisplayObjects/UniformTextureStretchRope.ts +0 -39
  84. package/src/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.ts +0 -174
  85. package/src/layers/GeomodelCanvasLayer.ts +0 -176
  86. package/src/layers/GeomodelLabelsLayer.ts +0 -619
  87. package/src/layers/GeomodelLayerV2.ts +0 -110
  88. package/src/layers/GridLayer.ts +0 -145
  89. package/src/layers/ImageCanvasLayer.ts +0 -55
  90. package/src/layers/ReferenceLineLayer.ts +0 -185
  91. package/src/layers/SchematicLayer.ts +0 -872
  92. package/src/layers/SeismicCanvasLayer.ts +0 -46
  93. package/src/layers/WellborePathLayer.ts +0 -129
  94. package/src/layers/base/CanvasLayer.ts +0 -102
  95. package/src/layers/base/HTMLLayer.ts +0 -70
  96. package/src/layers/base/Layer.ts +0 -217
  97. package/src/layers/base/PixiLayer.ts +0 -190
  98. package/src/layers/base/SVGLayer.ts +0 -63
  99. package/src/layers/base/index.ts +0 -5
  100. package/src/layers/index.ts +0 -16
  101. package/src/layers/schematicInterfaces.ts +0 -472
  102. package/src/utils/arc-length.ts +0 -66
  103. package/src/utils/binary-search.ts +0 -26
  104. package/src/utils/color.ts +0 -22
  105. package/src/utils/index.ts +0 -1
  106. package/src/utils/root-finder.ts +0 -78
  107. package/src/utils/text.ts +0 -88
  108. package/src/utils/vectorUtils.ts +0 -67
  109. package/src/vendor/pixi-dashed-line/index.ts +0 -394
@@ -1,619 +0,0 @@
1
- import Vector2 from '@equinor/videx-vector2';
2
- import { clamp } from '@equinor/videx-math';
3
-
4
- import { CanvasLayer } from './base/CanvasLayer';
5
- import { OnUpdateEvent, OnRescaleEvent, OnMountEvent } from '../interfaces';
6
- import { SurfaceArea, SurfaceLine, findSampleAtPos, SurfaceData } from '../datautils';
7
- import { SURFACE_LINE_WIDTH } from '../constants';
8
- import { LayerOptions } from './base/Layer';
9
-
10
- const DEFAULT_MARGINS = 18;
11
- const DEFAULT_MIN_FONT_SIZE = 8;
12
- const DEFAULT_MAX_FONT_SIZE = 13;
13
- const DEFAULT_TEXT_COLOR = 'black';
14
- const DEFAULT_FONT = 'Arial';
15
- const MAX_FONT_SIZE_IN_WORLD_COORDINATES = 70;
16
-
17
- export interface GeomodelLayerLabelsOptions<T extends SurfaceData> extends LayerOptions<T> {
18
- margins?: number;
19
- minFontSize?: number;
20
- maxFontSize?: number;
21
- textColor?: string;
22
- font?: string;
23
- }
24
-
25
- interface SurfaceAreaWithAvgTopDepth extends SurfaceArea {
26
- avgTopDepth: number;
27
- }
28
-
29
- export class GeomodelLabelsLayer<T extends SurfaceData> extends CanvasLayer<T> {
30
- defaultMargins: number = DEFAULT_MARGINS;
31
- defaultMinFontSize: number = DEFAULT_MIN_FONT_SIZE;
32
- defaultMaxFontSize: number = DEFAULT_MAX_FONT_SIZE;
33
- defaultTextColor: string = DEFAULT_TEXT_COLOR;
34
- defaultFont: string = DEFAULT_FONT;
35
-
36
- rescaleEvent: OnRescaleEvent;
37
- isLabelsOnLeftSide: boolean = true;
38
- maxFontSizeInWorldCoordinates: number = MAX_FONT_SIZE_IN_WORLD_COORDINATES;
39
- isXFlipped: boolean = false;
40
- areasWithAvgTopDepth: SurfaceAreaWithAvgTopDepth[] = null;
41
-
42
- constructor(id?: string, options?: GeomodelLayerLabelsOptions<T>) {
43
- super(id, options);
44
- this.render = this.render.bind(this);
45
- this.getMarginsInWorldCoordinates = this.getMarginsInWorldCoordinates.bind(this);
46
- this.getSurfacesAreaEdges = this.getSurfacesAreaEdges.bind(this);
47
- this.updateXFlipped = this.updateXFlipped.bind(this);
48
- this.generateSurfacesWithAvgDepth = this.generateSurfacesWithAvgDepth.bind(this);
49
- }
50
-
51
- get options(): GeomodelLayerLabelsOptions<T> {
52
- return this._options;
53
- }
54
-
55
- setData(data: T): void {
56
- super.setData(data);
57
- this.areasWithAvgTopDepth = null;
58
- }
59
-
60
- generateSurfacesWithAvgDepth(): void {
61
- const { areas } = this.data;
62
- this.areasWithAvgTopDepth = areas.reduce((acc: SurfaceAreaWithAvgTopDepth[], area: SurfaceArea) => {
63
- // Filter surfaces without label
64
- if (!area.label) {
65
- return acc;
66
- }
67
- const sumAndCount = area.data.reduce(
68
- (a: { sum: number; count: number }, d: number[]) => {
69
- if (d[1] != null) {
70
- a.sum += d[1];
71
- a.count++;
72
- }
73
- return a;
74
- },
75
- {
76
- sum: 0,
77
- count: 0,
78
- },
79
- );
80
- if (sumAndCount.count === 0) {
81
- return acc;
82
- }
83
- const avgTopDepth = sumAndCount.sum / sumAndCount.count;
84
-
85
- acc.push({
86
- ...area,
87
- avgTopDepth,
88
- });
89
- return acc;
90
- }, []);
91
- }
92
-
93
- onMount(event: OnMountEvent): void {
94
- super.onMount(event);
95
- }
96
-
97
- onUpdate(event: OnUpdateEvent<T>): void {
98
- super.onUpdate(event);
99
- this.render();
100
- }
101
-
102
- onRescale(event: OnRescaleEvent): void {
103
- this.rescaleEvent = event;
104
- this.updateXFlipped();
105
- this.resetTransform();
106
- this.render();
107
- }
108
-
109
- render(): void {
110
- if (!this.rescaleEvent) {
111
- return;
112
- }
113
-
114
- requestAnimationFrame(() => {
115
- this.clearCanvas();
116
-
117
- if (!this.data) {
118
- return;
119
- }
120
-
121
- if (!this.areasWithAvgTopDepth) {
122
- this.generateSurfacesWithAvgDepth();
123
- }
124
-
125
- this.drawAreaLabels();
126
- this.drawLineLabels();
127
- });
128
- }
129
-
130
- drawAreaLabels(): void {
131
- this.areasWithAvgTopDepth.forEach((s: SurfaceAreaWithAvgTopDepth, i: number, array: SurfaceAreaWithAvgTopDepth[]) => {
132
- const topmostSurfaceNotDrawnYet = array.reduce((acc: SurfaceAreaWithAvgTopDepth | null, v, index): SurfaceAreaWithAvgTopDepth | null => {
133
- if (index > i) {
134
- if (acc == null) {
135
- acc = v;
136
- } else {
137
- if (v.avgTopDepth < acc.avgTopDepth) {
138
- acc = v;
139
- }
140
- }
141
- }
142
- return acc;
143
- }, null);
144
-
145
- if (!topmostSurfaceNotDrawnYet) {
146
- return;
147
- }
148
-
149
- this.drawAreaLabel(s, topmostSurfaceNotDrawnYet, array, i);
150
- });
151
- }
152
-
153
- drawLineLabels(): void {
154
- this.data.lines.filter((surfaceLine: SurfaceLine) => surfaceLine.label).forEach((surfaceLine: SurfaceLine) => this.drawLineLabel(surfaceLine));
155
- }
156
-
157
- drawAreaLabel = (surfaceArea: SurfaceArea, nextSurfaceArea: SurfaceArea, surfaces: SurfaceArea[], i: number): void => {
158
- const { data } = surfaceArea;
159
- const { ctx, maxFontSizeInWorldCoordinates, isXFlipped } = this;
160
- const { xScale, yScale, xRatio, yRatio, zFactor } = this.rescaleEvent;
161
- let isLabelsOnLeftSide = this.checkDrawLabelsOnLeftSide();
162
- const margins = (this.options.margins || this.defaultMargins) * (isXFlipped ? -1 : 1);
163
- const marginsInWorldCoords = margins / xRatio;
164
- const minFontSize = this.options.minFontSize || this.defaultMinFontSize;
165
- const maxFontSize = this.options.maxFontSize || this.defaultMaxFontSize;
166
-
167
- let fontSizeInWorldCoords = maxFontSize / yRatio;
168
- if (fontSizeInWorldCoords > maxFontSizeInWorldCoordinates) {
169
- fontSizeInWorldCoords = maxFontSizeInWorldCoordinates;
170
- if (fontSizeInWorldCoords * yRatio < minFontSize) {
171
- fontSizeInWorldCoords = minFontSize / yRatio;
172
- }
173
- }
174
-
175
- const leftEdge = xScale.invert(xScale.range()[0]) + marginsInWorldCoords;
176
- const rightEdge = xScale.invert(xScale.range()[1]) - marginsInWorldCoords;
177
- const [surfaceAreaLeftEdge, surfaceAreaRightEdge] = this.getSurfacesAreaEdges();
178
-
179
- // Get label metrics
180
- ctx.save();
181
- ctx.font = `${fontSizeInWorldCoords * yRatio}px ${this.options.font || this.defaultFont}`;
182
- let labelMetrics = ctx.measureText(surfaceArea.label);
183
- let labelLengthInWorldCoords = labelMetrics.width / xRatio;
184
-
185
- // Check if label will fit horizontally
186
- if (isLabelsOnLeftSide) {
187
- const labelRightEdge = leftEdge + (isXFlipped ? -labelLengthInWorldCoords : labelLengthInWorldCoords);
188
- if ((!isXFlipped && labelRightEdge > surfaceAreaRightEdge) || (isXFlipped && labelRightEdge < surfaceAreaRightEdge)) {
189
- isLabelsOnLeftSide = false;
190
- }
191
- } else {
192
- const labelLeftEdge = rightEdge + (isXFlipped ? labelLengthInWorldCoords : -labelLengthInWorldCoords);
193
- if ((!isXFlipped && labelLeftEdge < surfaceAreaLeftEdge) || (isXFlipped && labelLeftEdge > surfaceAreaLeftEdge)) {
194
- isLabelsOnLeftSide = true;
195
- }
196
- }
197
-
198
- // Find edge where to draw
199
- let startPos;
200
- const portionOfLabelLengthUsedForPosCalc = 0.07;
201
- if (isLabelsOnLeftSide) {
202
- startPos = isXFlipped ? Math.min(surfaceAreaLeftEdge, leftEdge) : Math.max(surfaceAreaLeftEdge, leftEdge);
203
- } else {
204
- startPos = isXFlipped ? Math.max(surfaceAreaRightEdge, rightEdge) : Math.min(surfaceAreaRightEdge, rightEdge);
205
- }
206
-
207
- const topEdge = yScale.invert(yScale.range()[0]);
208
- const bottomEdge = yScale.invert(yScale.range()[1]);
209
-
210
- // Calculate where to sample points
211
- const dirSteps = 5;
212
- const posSteps = 3;
213
- const posStep =
214
- portionOfLabelLengthUsedForPosCalc * (labelLengthInWorldCoords / posSteps) * (isLabelsOnLeftSide ? 1 : -1) * (isXFlipped ? -1 : 1);
215
- const dirStep = (labelLengthInWorldCoords / dirSteps) * (isLabelsOnLeftSide ? 1 : -1) * (isXFlipped ? -1 : 1);
216
-
217
- // Sample points from top and calculate position
218
- const topData = data.map((d) => [d[0], d[1]]);
219
- const topPos = this.calcPos(topData, startPos, posSteps, posStep, topEdge, bottomEdge);
220
- if (!topPos) {
221
- return;
222
- }
223
-
224
- // Sample points from bottom and calculate position
225
- const bottomData = data.map((d) => [d[0], d[2]]);
226
- let bottomPos = this.calcPos(
227
- bottomData,
228
- startPos,
229
- posSteps,
230
- posStep,
231
- topEdge,
232
- bottomEdge,
233
- nextSurfaceArea ? nextSurfaceArea.data.map((d) => [d[0], d[1]]) : null,
234
- surfaces,
235
- i,
236
- );
237
- if (!bottomPos) {
238
- bottomPos = new Vector2(topPos.x, bottomEdge);
239
- }
240
-
241
- // Check if there is enough height for label
242
- const thickness = bottomPos.y - topPos.y;
243
- if (thickness < fontSizeInWorldCoords) {
244
- // Check minimum fontsize
245
- if (thickness * yRatio < minFontSize) {
246
- return;
247
- }
248
- // Use reduced fontsize
249
- fontSizeInWorldCoords = thickness;
250
- ctx.font = `${fontSizeInWorldCoords * yRatio}px ${this.options.font || this.defaultFont}`;
251
- labelMetrics = ctx.measureText(surfaceArea.label);
252
- labelLengthInWorldCoords = labelMetrics.width / xRatio;
253
- }
254
- // Sample points from top and bottom and calculate direction vector
255
- const initialDirVec = isLabelsOnLeftSide !== isXFlipped ? Vector2.right : Vector2.left;
256
- const areaDir = this.calcAreaDir(
257
- topData,
258
- bottomData,
259
- startPos,
260
- dirSteps,
261
- dirStep,
262
- initialDirVec,
263
- topEdge,
264
- bottomEdge,
265
- 0,
266
- Math.PI / 4,
267
- 4,
268
- nextSurfaceArea ? nextSurfaceArea.data.map((d) => [d[0], d[1]]) : null,
269
- surfaces,
270
- i,
271
- );
272
- const scaledAngle = Math.atan(Math.tan(areaDir) * zFactor);
273
-
274
- // Draw label
275
- const textX = startPos;
276
- const textY = (topPos.y + bottomPos.y) / 2;
277
- const textAngle = isXFlipped ? -scaledAngle : scaledAngle;
278
- ctx.textAlign = isLabelsOnLeftSide ? 'left' : 'right';
279
- ctx.translate(xScale(textX), yScale(textY));
280
- ctx.rotate(textAngle);
281
- ctx.fillStyle = this.options.textColor || this.defaultTextColor;
282
- ctx.font = `${fontSizeInWorldCoords * yRatio}px ${this.options.font || this.defaultFont}`;
283
- ctx.textBaseline = 'middle';
284
- ctx.fillText(surfaceArea.label, 0, 0);
285
-
286
- ctx.restore();
287
- };
288
-
289
- drawLineLabel = (s: SurfaceLine): void => {
290
- const { ctx, isXFlipped } = this;
291
- const { xScale, yScale, xRatio, yRatio, zFactor } = this.rescaleEvent;
292
- const isLabelsOnLeftSide = this.checkDrawLabelsOnLeftSide();
293
- const marginsInWorldCoords = this.getMarginsInWorldCoordinates();
294
- const maxFontSize = this.options.maxFontSize || this.defaultMaxFontSize;
295
-
296
- const fontSizeInWorldCoords = maxFontSize / yRatio;
297
-
298
- ctx.save();
299
- ctx.font = `${fontSizeInWorldCoords * yRatio}px ${this.options.font || this.defaultFont}`;
300
- const labelMetrics = ctx.measureText(s.label);
301
- const labelLengthInWorldCoords = labelMetrics.width / xRatio;
302
-
303
- const leftEdge = xScale.invert(xScale.range()[0]) + marginsInWorldCoords;
304
- const rightEdge = xScale.invert(xScale.range()[1]) - marginsInWorldCoords;
305
- const [surfaceAreaLeftEdge, surfaceAreaRightEdge] = this.getSurfacesAreaEdges();
306
-
307
- // Find edge where to draw
308
- let startPos;
309
- const steps = 5;
310
- if (isLabelsOnLeftSide) {
311
- startPos = isXFlipped ? Math.max(surfaceAreaRightEdge, rightEdge) : Math.min(surfaceAreaRightEdge, rightEdge);
312
- } else {
313
- startPos = isXFlipped ? Math.min(surfaceAreaLeftEdge, leftEdge) : Math.max(surfaceAreaLeftEdge, leftEdge);
314
- }
315
-
316
- // Calculate where to sample points
317
- const step = (labelLengthInWorldCoords / steps) * (isLabelsOnLeftSide ? -1 : 1);
318
-
319
- // Sample points and calculate position and direction vector
320
- const { data } = s;
321
- const pos = this.calcPos(data, startPos, steps, step);
322
- const dir = this.calcLineDir(data, startPos, steps, step, zFactor, isLabelsOnLeftSide ? Vector2.left : Vector2.right);
323
- if (!pos || !dir) {
324
- return;
325
- }
326
-
327
- // Calculate position and direction for label
328
- const textX = startPos;
329
- const textY = pos.y - SURFACE_LINE_WIDTH - fontSizeInWorldCoords / 2;
330
- const textDir = Vector2.angleRight(dir) - (isLabelsOnLeftSide ? Math.PI : 0);
331
-
332
- // Draw label
333
- ctx.textAlign = isLabelsOnLeftSide ? 'right' : 'left';
334
- ctx.translate(xScale(textX), yScale(textY));
335
- ctx.rotate(textDir);
336
- ctx.fillStyle = this.colorToCSSColor(s.color);
337
- ctx.textBaseline = 'middle';
338
- ctx.fillText(s.label, 0, 0);
339
-
340
- ctx.restore();
341
- };
342
-
343
- colorToCSSColor(color: number | string): string {
344
- if (typeof color === 'string') {
345
- return color;
346
- }
347
-
348
- let hexString = color.toString(16);
349
- // eslint-disable-next-line no-magic-numbers
350
- hexString = '000000'.substr(0, 6 - hexString.length) + hexString;
351
- return `#${hexString}`;
352
- }
353
-
354
- calcPos(
355
- data: number[][],
356
- offset: number,
357
- count: number,
358
- step: number,
359
- topLimit: number = null,
360
- bottomLimit: number = null,
361
- alternativeSurfaceData: number[][] = null,
362
- surfaces: SurfaceArea[] | null = null,
363
- currentSurfaceIndex: number = null,
364
- ): Vector2 {
365
- const pos = Vector2.zero.mutable;
366
- let samples = 0;
367
- for (let i = 0; i < count; i++) {
368
- const x = offset + i * step;
369
- const y = findSampleAtPos(data, x, topLimit, bottomLimit);
370
- if (y) {
371
- const alternativeY = this.getAlternativeYValueIfAvailable(x, topLimit, bottomLimit, alternativeSurfaceData, surfaces, currentSurfaceIndex);
372
- // Use topmost of value from current surface and alternative surface
373
- const usedY = alternativeY ? Math.min(y, alternativeY) : y;
374
- pos.add(x, usedY);
375
- samples++;
376
- }
377
- }
378
-
379
- if (samples === 0) {
380
- return null;
381
- }
382
-
383
- return Vector2.divide(pos, samples);
384
- }
385
-
386
- getAlternativeYValueIfAvailable(
387
- x: number,
388
- topLimit: number,
389
- bottomLimit: number,
390
- alternativeSurfaceData: number[][],
391
- surfaces: SurfaceArea[] | null,
392
- currentSurfaceIndex: number,
393
- ): number {
394
- if (!alternativeSurfaceData) {
395
- return null;
396
- }
397
- // Find sample from passed in surface data
398
- let altY = findSampleAtPos(alternativeSurfaceData, x, topLimit, bottomLimit);
399
- if (altY == null && surfaces && currentSurfaceIndex != null) {
400
- //Find topmost surface after current which gives us data
401
- let si = currentSurfaceIndex + 1;
402
- while (altY == null && si < surfaces.length) {
403
- const altSurface = surfaces[si++];
404
- altY = findSampleAtPos(
405
- altSurface.data.map((d: number[]) => [d[0], d[1]]),
406
- x,
407
- topLimit,
408
- bottomLimit,
409
- );
410
- }
411
- }
412
- return altY;
413
- }
414
-
415
- calcLineDir(
416
- data: number[][],
417
- offset: number,
418
- count: number,
419
- step: number,
420
- zFactor: number,
421
- initalVector: Vector2 = Vector2.left,
422
- topLimit: number = null,
423
- bottomLimit: number = null,
424
- ): Vector2 {
425
- const dir = initalVector.mutable;
426
-
427
- const startY = findSampleAtPos(data, offset, topLimit, bottomLimit);
428
- if (startY === null) {
429
- return dir;
430
- }
431
-
432
- const vecAtEnd = new Vector2(offset, startY * zFactor);
433
- const tmpVec = Vector2.zero.mutable;
434
- for (let i = 1; i <= count; i++) {
435
- const x = offset + i * step;
436
- const y = findSampleAtPos(data, offset, topLimit, bottomLimit);
437
- if (y !== null) {
438
- tmpVec.set(x, y * zFactor);
439
- tmpVec.sub(vecAtEnd);
440
- dir.add(tmpVec);
441
- }
442
- }
443
-
444
- return dir;
445
- }
446
-
447
- calcAreaDir(
448
- top: number[][],
449
- bottom: number[][],
450
- offset: number,
451
- count: number,
452
- step: number,
453
- initalVector: Vector2 = Vector2.left,
454
- topLimit: number = null,
455
- bottomLimit: number = null,
456
- minReductionAngle: number = 0,
457
- maxReductionAngle: number = Math.PI / 4,
458
- angleReductionExponent: number = 4,
459
- alternativeSurfaceBottomData: number[][] = null,
460
- surfaces: SurfaceArea[] | null = null,
461
- currentSurfaceIndex: number = null,
462
- ): number {
463
- const angles: number[] = [];
464
- const tmpVec = Vector2.zero.mutable;
465
- let vecAtEnd;
466
- for (let i = 0; i <= count; i++) {
467
- const x = offset + i * step;
468
- const topY = findSampleAtPos(top, x, topLimit, bottomLimit);
469
- const bottomY = findSampleAtPos(bottom, x, topLimit, bottomLimit) || bottomLimit;
470
- // Find position of next surface in case it's higher than current base
471
- const alternativeBottomY = this.getAlternativeYValueIfAvailable(
472
- x,
473
- topLimit,
474
- bottomLimit,
475
- alternativeSurfaceBottomData,
476
- surfaces,
477
- currentSurfaceIndex,
478
- );
479
- // Use topmost of value from current surface and alternative surface
480
- const usedBottomY = alternativeBottomY ? Math.min(bottomY, alternativeBottomY) : bottomY;
481
- if (i === 0) {
482
- if (topY === null) {
483
- return Vector2.angleRight(initalVector);
484
- }
485
- const startY = (topY + usedBottomY) / 2;
486
- vecAtEnd = new Vector2(offset, startY);
487
- } else {
488
- if (topY !== null) {
489
- tmpVec.set(x, (topY + usedBottomY) / 2);
490
- tmpVec.sub(vecAtEnd);
491
-
492
- angles.push(Vector2.angleRight(tmpVec));
493
- } else {
494
- angles.push(Vector2.angleRight(initalVector));
495
- }
496
- }
497
- }
498
-
499
- const refAngle = angles[0];
500
- const offsetAngles = angles.map((d: number) => d - refAngle);
501
- let factors = 0;
502
- const offsetSum = offsetAngles.reduce((acc: number, v: number) => {
503
- const ratio = (Math.abs(v) - minReductionAngle) / maxReductionAngle;
504
- const factor = Math.pow(1 - clamp(ratio, 0, 1), angleReductionExponent);
505
- factors += factor;
506
- return acc + v * factor;
507
- }, 0);
508
- const angle = offsetSum / factors + refAngle;
509
- return angle;
510
- }
511
-
512
- updateXFlipped(): void {
513
- const { xBounds } = this.rescaleEvent;
514
- this.isXFlipped = xBounds[0] > xBounds[1];
515
- }
516
-
517
- getMarginsInWorldCoordinates(): number {
518
- const { xRatio } = this.rescaleEvent;
519
- const margins = (this.options.margins || this.defaultMargins) * (this.isXFlipped ? -1 : 1);
520
- const marginsInWorldCoords = margins / xRatio;
521
- return marginsInWorldCoords;
522
- }
523
-
524
- getSurfacesAreaEdges(): number[] {
525
- const endPoints = this.data.areas.reduce((acc, area) => {
526
- const { data } = area;
527
- const firstValidPoint = data.find((d: number[]) => d[1] != null);
528
- if (firstValidPoint) {
529
- acc.push(firstValidPoint[0]);
530
- }
531
- // TODO: Use findLast() when TypeScript stops complaining about it
532
- for (let i = data.length - 1; i >= 0; i--) {
533
- if (data[i][1] != null) {
534
- acc.push(data[i][0]);
535
- break;
536
- }
537
- }
538
-
539
- return acc;
540
- }, []);
541
- endPoints.push(
542
- ...this.data.lines.reduce((acc, line) => {
543
- const { data } = line;
544
- const firstValidPoint = data.find((d: number[]) => d[1] != null);
545
- if (firstValidPoint) {
546
- acc.push(firstValidPoint[0]);
547
- }
548
- // TODO: Use findLast() when TypeScript stops complaining about it
549
- for (let i = data.length - 1; i >= 0; i--) {
550
- if (data[i][1] != null) {
551
- acc.push(data[i][0]);
552
- break;
553
- }
554
- }
555
- return acc;
556
- }, []),
557
- );
558
-
559
- const minX = Math.min(...endPoints);
560
- const maxX = Math.max(...endPoints);
561
- const marginsInWorldCoords = this.getMarginsInWorldCoordinates();
562
- const { isXFlipped } = this;
563
- const surfaceAreaLeftEdge = isXFlipped ? maxX + marginsInWorldCoords : minX + marginsInWorldCoords;
564
- const surfaceAreaRightEdge = isXFlipped ? minX - marginsInWorldCoords : maxX - marginsInWorldCoords;
565
- return [surfaceAreaLeftEdge, surfaceAreaRightEdge];
566
- }
567
-
568
- checkDrawLabelsOnLeftSide(): boolean {
569
- const { referenceSystem, isXFlipped } = this;
570
- if (!referenceSystem) {
571
- return true;
572
- }
573
-
574
- const { xScale, yScale, xRatio } = this.rescaleEvent;
575
- const t = 200; // TODO: Use actual size of largest label or average size of all
576
-
577
- const [dx1, dx2] = xScale.domain();
578
- const [dy1, dy2] = yScale.domain();
579
-
580
- let top = referenceSystem.interpolators.curtain.getIntersects(dy1, 1, 0) as number[][];
581
- if (top.length === 0) {
582
- top = [referenceSystem.interpolators.curtain.getPointAt(0.0) as number[]];
583
- }
584
- let bottom = referenceSystem.interpolators.curtain.getIntersects(dy2, 1, 0) as number[][];
585
- if (bottom.length === 0) {
586
- bottom = [referenceSystem.interpolators.curtain.getPointAt(1.0) as number[]];
587
- }
588
-
589
- const maxX = Math.max(top[0][0], bottom[0][0]);
590
- const minX = Math.min(top[0][0], bottom[0][0]);
591
-
592
- const wbBBox = {
593
- left: isXFlipped ? maxX : minX,
594
- right: isXFlipped ? minX : maxX,
595
- };
596
-
597
- const margin = this.getMarginsInWorldCoordinates();
598
- const screenLeftEdge = dx1 + margin;
599
- const screenRightEdge = dx2 - margin;
600
-
601
- const [surfaceAreaLeftEdge, surfaceAreaRightEdge] = this.getSurfacesAreaEdges();
602
-
603
- const leftLimit = isXFlipped ? Math.min(screenLeftEdge, surfaceAreaLeftEdge) : Math.max(screenLeftEdge, surfaceAreaLeftEdge);
604
- const rightLimit = isXFlipped ? Math.max(screenRightEdge, surfaceAreaRightEdge) : Math.min(screenRightEdge, surfaceAreaRightEdge);
605
-
606
- const spaceOnLeftSide = Math.max(isXFlipped ? leftLimit - wbBBox.left : wbBBox.left - leftLimit, 0);
607
- const spaceOnRightSide = Math.max(isXFlipped ? wbBBox.right - rightLimit : rightLimit - wbBBox.right, 0);
608
-
609
- const spaceOnLeftSideInScreenCoordinates = spaceOnLeftSide * xRatio;
610
- const spaceOnRightSideInScreenCoordinates = spaceOnRightSide * xRatio;
611
- const isLabelsOnLeftSide =
612
- spaceOnLeftSide > spaceOnRightSide ||
613
- spaceOnLeftSideInScreenCoordinates > t ||
614
- (spaceOnLeftSideInScreenCoordinates < t && spaceOnRightSideInScreenCoordinates < t && isXFlipped) ||
615
- bottom[0][1] < dy1;
616
-
617
- return isLabelsOnLeftSide;
618
- }
619
- }