@equinor/esv-intersection 3.0.4 → 3.0.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/README.md +18 -3
- package/dist/components/axis.d.ts +48 -0
- package/dist/components/axis.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/control/ExtendedCurveInterpolator.d.ts +59 -0
- package/dist/control/ExtendedCurveInterpolator.d.ts.map +1 -0
- package/dist/control/IntersectionReferenceSystem.d.ts +97 -0
- package/dist/control/IntersectionReferenceSystem.d.ts.map +1 -0
- package/dist/control/LayerManager.d.ts +77 -0
- package/dist/control/LayerManager.d.ts.map +1 -0
- package/dist/control/MainController.d.ts +155 -0
- package/dist/control/MainController.d.ts.map +1 -0
- package/dist/control/ZoomPanHandler.d.ts +159 -0
- package/dist/control/ZoomPanHandler.d.ts.map +1 -0
- package/dist/control/index.d.ts +6 -0
- package/dist/control/index.d.ts.map +1 -0
- package/dist/control/interfaces.d.ts +38 -0
- package/dist/control/interfaces.d.ts.map +1 -0
- package/dist/control/overlay.d.ts +21 -0
- package/dist/control/overlay.d.ts.map +1 -0
- package/dist/datautils/colortable.d.ts +2 -0
- package/dist/datautils/colortable.d.ts.map +1 -0
- package/dist/datautils/findsample.d.ts +3 -0
- package/dist/datautils/findsample.d.ts.map +1 -0
- package/dist/datautils/index.d.ts +7 -0
- package/dist/datautils/index.d.ts.map +1 -0
- package/dist/datautils/interfaces.d.ts +64 -0
- package/dist/datautils/interfaces.d.ts.map +1 -0
- package/dist/datautils/picks.d.ts +75 -0
- package/dist/datautils/picks.d.ts.map +1 -0
- package/dist/datautils/schematicShapeGenerator.d.ts +60 -0
- package/dist/datautils/schematicShapeGenerator.d.ts.map +1 -0
- package/dist/datautils/seismicimage.d.ts +46 -0
- package/dist/datautils/seismicimage.d.ts.map +1 -0
- package/dist/datautils/surfacedata.d.ts +11 -0
- package/dist/datautils/surfacedata.d.ts.map +1 -0
- package/dist/datautils/trajectory.d.ts +15 -0
- package/dist/datautils/trajectory.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +141 -143
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/layers/CalloutCanvasLayer.d.ts +61 -0
- package/dist/layers/CalloutCanvasLayer.d.ts.map +1 -0
- package/dist/layers/CustomDisplayObjects/ComplexRope.d.ts +22 -0
- package/dist/layers/CustomDisplayObjects/ComplexRope.d.ts.map +1 -0
- package/dist/layers/CustomDisplayObjects/ComplexRopeGeometry.d.ts +24 -0
- package/dist/layers/CustomDisplayObjects/ComplexRopeGeometry.d.ts.map +1 -0
- package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRope.d.ts +21 -0
- package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRope.d.ts.map +1 -0
- package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.d.ts +27 -0
- package/dist/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.d.ts.map +1 -0
- package/dist/layers/CustomDisplayObjects/UniformTextureStretchRope.d.ts +18 -0
- package/dist/layers/CustomDisplayObjects/UniformTextureStretchRope.d.ts.map +1 -0
- package/dist/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.d.ts +25 -0
- package/dist/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.d.ts.map +1 -0
- package/dist/layers/GeomodelCanvasLayer.d.ts +29 -0
- package/dist/layers/GeomodelCanvasLayer.d.ts.map +1 -0
- package/dist/layers/GeomodelLabelsLayer.d.ts +50 -0
- package/dist/layers/GeomodelLabelsLayer.d.ts.map +1 -0
- package/dist/layers/GeomodelLayerV2.d.ts +13 -0
- package/dist/layers/GeomodelLayerV2.d.ts.map +1 -0
- package/dist/layers/GridLayer.d.ts +30 -0
- package/dist/layers/GridLayer.d.ts.map +1 -0
- package/dist/layers/ImageCanvasLayer.d.ts +21 -0
- package/dist/layers/ImageCanvasLayer.d.ts.map +1 -0
- package/dist/layers/ReferenceLineLayer.d.ts +30 -0
- package/dist/layers/ReferenceLineLayer.d.ts.map +1 -0
- package/dist/layers/SchematicLayer.d.ts +114 -0
- package/dist/layers/SchematicLayer.d.ts.map +1 -0
- package/dist/layers/SeismicCanvasLayer.d.ts +19 -0
- package/dist/layers/SeismicCanvasLayer.d.ts.map +1 -0
- package/dist/layers/WellborePathLayer.d.ts +18 -0
- package/dist/layers/WellborePathLayer.d.ts.map +1 -0
- package/dist/layers/base/CanvasLayer.d.ts +20 -0
- package/dist/layers/base/CanvasLayer.d.ts.map +1 -0
- package/dist/layers/base/HTMLLayer.d.ts +14 -0
- package/dist/layers/base/HTMLLayer.d.ts.map +1 -0
- package/dist/layers/base/Layer.d.ts +70 -0
- package/dist/layers/base/Layer.d.ts.map +1 -0
- package/dist/layers/base/PixiLayer.d.ts +33 -0
- package/dist/layers/base/PixiLayer.d.ts.map +1 -0
- package/dist/layers/base/SVGLayer.d.ts +14 -0
- package/dist/layers/base/SVGLayer.d.ts.map +1 -0
- package/dist/layers/base/index.d.ts +6 -0
- package/dist/layers/base/index.d.ts.map +1 -0
- package/dist/layers/index.d.ts +17 -0
- package/dist/layers/index.d.ts.map +1 -0
- package/dist/layers/schematicInterfaces.d.ts +210 -0
- package/dist/layers/schematicInterfaces.d.ts.map +1 -0
- package/dist/utils/arc-length.d.ts +24 -0
- package/dist/utils/arc-length.d.ts.map +1 -0
- package/dist/utils/binary-search.d.ts +9 -0
- package/dist/utils/binary-search.d.ts.map +1 -0
- package/dist/utils/color.d.ts +6 -0
- package/dist/utils/color.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/root-finder.d.ts +35 -0
- package/dist/utils/root-finder.d.ts.map +1 -0
- package/dist/utils/text.d.ts +15 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/vectorUtils.d.ts +16 -0
- package/dist/utils/vectorUtils.d.ts.map +1 -0
- package/dist/vendor/pixi-dashed-line/index.d.ts +57 -0
- package/dist/vendor/pixi-dashed-line/index.d.ts.map +1 -0
- package/package.json +28 -21
- package/src/.eslintrc.json +5 -0
- package/src/components/axis.ts +247 -0
- package/src/components/index.ts +1 -0
- package/src/control/ExtendedCurveInterpolator.ts +155 -0
- package/src/control/IntersectionReferenceSystem.ts +391 -0
- package/src/control/LayerManager.ts +294 -0
- package/src/control/MainController.ts +296 -0
- package/src/control/ZoomPanHandler.ts +436 -0
- package/src/control/index.ts +5 -0
- package/src/control/interfaces.ts +42 -0
- package/src/control/overlay.ts +118 -0
- package/src/datautils/colortable.ts +14 -0
- package/src/datautils/findsample.ts +64 -0
- package/src/datautils/index.ts +6 -0
- package/src/datautils/interfaces.ts +68 -0
- package/src/datautils/picks.ts +328 -0
- package/src/datautils/schematicShapeGenerator.ts +1008 -0
- package/src/datautils/seismicimage.ts +180 -0
- package/src/datautils/surfacedata.ts +317 -0
- package/src/datautils/trajectory.ts +206 -0
- package/src/layers/CalloutCanvasLayer.ts +338 -0
- package/src/layers/CustomDisplayObjects/ComplexRope.ts +44 -0
- package/src/layers/CustomDisplayObjects/ComplexRopeGeometry.ts +184 -0
- package/src/layers/CustomDisplayObjects/FixedWidthSimpleRope.ts +41 -0
- package/src/layers/CustomDisplayObjects/FixedWidthSimpleRopeGeometry.ts +149 -0
- package/src/layers/CustomDisplayObjects/UniformTextureStretchRope.ts +39 -0
- package/src/layers/CustomDisplayObjects/UniformTextureStretchRopeGeometry.ts +174 -0
- package/src/layers/GeomodelCanvasLayer.ts +176 -0
- package/src/layers/GeomodelLabelsLayer.ts +615 -0
- package/src/layers/GeomodelLayerV2.ts +111 -0
- package/src/layers/GridLayer.ts +145 -0
- package/src/layers/ImageCanvasLayer.ts +55 -0
- package/src/layers/ReferenceLineLayer.ts +185 -0
- package/src/layers/SchematicLayer.ts +870 -0
- package/src/layers/SeismicCanvasLayer.ts +46 -0
- package/src/layers/WellborePathLayer.ts +129 -0
- package/src/layers/base/CanvasLayer.ts +102 -0
- package/src/layers/base/HTMLLayer.ts +70 -0
- package/src/layers/base/Layer.ts +217 -0
- package/src/layers/base/PixiLayer.ts +190 -0
- package/src/layers/base/SVGLayer.ts +63 -0
- package/src/layers/base/index.ts +5 -0
- package/src/layers/index.ts +16 -0
- package/src/layers/schematicInterfaces.ts +472 -0
- package/src/tsconfig.json +9 -0
- package/src/utils/arc-length.ts +66 -0
- package/src/utils/binary-search.ts +26 -0
- package/src/utils/color.ts +22 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/root-finder.ts +78 -0
- package/src/utils/text.ts +88 -0
- package/src/utils/vectorUtils.ts +67 -0
- package/src/vendor/pixi-dashed-line/index.ts +390 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { select, Selection } from 'd3-selection';
|
|
2
|
+
import { scaleLinear, ScaleLinear } from 'd3-scale';
|
|
3
|
+
import { zoom, zoomIdentity, ZoomBehavior, ZoomTransform } from 'd3-zoom';
|
|
4
|
+
|
|
5
|
+
import { ZoomAndPanOptions, OnRescaleEvent } from '../interfaces';
|
|
6
|
+
|
|
7
|
+
const DEFAULT_MIN_ZOOM_LEVEL = 0.1;
|
|
8
|
+
const DEFAULT_MAX_ZOOM_LEVEL = 256;
|
|
9
|
+
|
|
10
|
+
export type RescaleFunction = (event: OnRescaleEvent) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Handle zoom and pan for intersection layers
|
|
13
|
+
*/
|
|
14
|
+
export class ZoomPanHandler {
|
|
15
|
+
zoom: ZoomBehavior<Element, unknown> = null;
|
|
16
|
+
elm: HTMLElement = null;
|
|
17
|
+
container: Selection<HTMLElement, unknown, null, undefined> = null;
|
|
18
|
+
onRescale: RescaleFunction = null;
|
|
19
|
+
options: ZoomAndPanOptions = null;
|
|
20
|
+
xBounds: [number, number] = [0, 1];
|
|
21
|
+
yBounds: [number, number] = [0, 1];
|
|
22
|
+
translateBoundsX: [number, number] = [0, 1];
|
|
23
|
+
translateBoundsY: [number, number] = [0, 1];
|
|
24
|
+
scaleX: ScaleLinear<number, number> = null;
|
|
25
|
+
scaleY: ScaleLinear<number, number> = null;
|
|
26
|
+
_zFactor: number = 1;
|
|
27
|
+
_enableTranslateExtent: boolean;
|
|
28
|
+
currentTransform: ZoomTransform;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Constructor
|
|
32
|
+
* @param elm, -
|
|
33
|
+
* @param options - options
|
|
34
|
+
*/
|
|
35
|
+
constructor(
|
|
36
|
+
elm: HTMLElement,
|
|
37
|
+
onRescale: RescaleFunction,
|
|
38
|
+
options: ZoomAndPanOptions = { maxZoomLevel: DEFAULT_MAX_ZOOM_LEVEL, minZoomLevel: DEFAULT_MIN_ZOOM_LEVEL },
|
|
39
|
+
) {
|
|
40
|
+
this.container = select(elm);
|
|
41
|
+
this.options = options;
|
|
42
|
+
|
|
43
|
+
this.onRescale = onRescale;
|
|
44
|
+
|
|
45
|
+
this.onZoom = this.onZoom.bind(this);
|
|
46
|
+
this.calculateTransform = this.calculateTransform.bind(this);
|
|
47
|
+
this.applyTransform = this.applyTransform.bind(this);
|
|
48
|
+
this.recalculateZoomTransform = this.recalculateZoomTransform.bind(this);
|
|
49
|
+
this.rescale = this.rescale.bind(this);
|
|
50
|
+
|
|
51
|
+
this.adjustToSize = this.adjustToSize.bind(this);
|
|
52
|
+
this.setViewport = this.setViewport.bind(this);
|
|
53
|
+
|
|
54
|
+
this.currentStateAsEvent = this.currentStateAsEvent.bind(this);
|
|
55
|
+
|
|
56
|
+
this.updateTranslateExtent = this.updateTranslateExtent.bind(this);
|
|
57
|
+
|
|
58
|
+
this.scaleX = scaleLinear().domain(this.xBounds).range([0, 1]);
|
|
59
|
+
this.scaleY = scaleLinear().domain(this.yBounds).range([0, 1]);
|
|
60
|
+
|
|
61
|
+
this.init();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Getter returning width of target
|
|
66
|
+
* @returns width
|
|
67
|
+
*/
|
|
68
|
+
get width(): number {
|
|
69
|
+
return this.scaleX.range()[1];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Getter returning height of target
|
|
74
|
+
* @returns height
|
|
75
|
+
*/
|
|
76
|
+
get height(): number {
|
|
77
|
+
return this.scaleY.range()[1];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Getter which calculate span from x bounds
|
|
82
|
+
* @returns x span
|
|
83
|
+
*/
|
|
84
|
+
get xSpan(): number {
|
|
85
|
+
const { xBounds } = this;
|
|
86
|
+
const xspan: number = Math.abs(xBounds[1] - xBounds[0]);
|
|
87
|
+
return xspan;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Calculate span from y bounds
|
|
92
|
+
* @returns y span
|
|
93
|
+
*/
|
|
94
|
+
get ySpan(): number {
|
|
95
|
+
const { yBounds } = this;
|
|
96
|
+
const yspan: number = Math.abs(yBounds[1] - yBounds[0]);
|
|
97
|
+
return yspan;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Ratio between height and width
|
|
102
|
+
* @returns ratio
|
|
103
|
+
*/
|
|
104
|
+
get viewportRatio(): number {
|
|
105
|
+
const ratio: number = this.width / (this.height || 1);
|
|
106
|
+
return ratio;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* x ratios screen to value ratio
|
|
111
|
+
* @returns ratio
|
|
112
|
+
*/
|
|
113
|
+
get xRatio(): number {
|
|
114
|
+
const domain: number[] = this.scaleX.domain();
|
|
115
|
+
const ratio: number = Math.abs(this.width / (domain[1] - domain[0]));
|
|
116
|
+
return ratio;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* y scale screen to value ratio
|
|
121
|
+
* @returns ratio
|
|
122
|
+
*/
|
|
123
|
+
get yRatio(): number {
|
|
124
|
+
const domain: number[] = this.scaleY.domain();
|
|
125
|
+
const ratio: number = Math.abs(this.height / (domain[1] - domain[0]));
|
|
126
|
+
return ratio;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get z-factor
|
|
131
|
+
* @returns z-factor
|
|
132
|
+
*/
|
|
133
|
+
get zFactor(): number {
|
|
134
|
+
return this._zFactor;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Set z factor
|
|
139
|
+
* @param factor
|
|
140
|
+
*/
|
|
141
|
+
set zFactor(factor: number) {
|
|
142
|
+
this._zFactor = factor;
|
|
143
|
+
this.recalculateZoomTransform();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Check if x is inverted (right to left is positive) from x bounds
|
|
148
|
+
* @returns true if inverted
|
|
149
|
+
*/
|
|
150
|
+
get isXInverted(): boolean {
|
|
151
|
+
return this.xBounds[1] < this.xBounds[0];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if y is inverted (bottom to top is positive) from y bounds
|
|
156
|
+
* @returns true if inverted
|
|
157
|
+
*/
|
|
158
|
+
get isYInverted(): boolean {
|
|
159
|
+
return this.yBounds[1] < this.yBounds[0];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get if enable translate extent (pan limit)
|
|
164
|
+
* @returns true if enabled
|
|
165
|
+
*/
|
|
166
|
+
get enableTranslateExtent(): boolean {
|
|
167
|
+
return this._enableTranslateExtent;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Set enable translate extent (pan limit)
|
|
172
|
+
* @param enabled - If should be enabled
|
|
173
|
+
*/
|
|
174
|
+
set enableTranslateExtent(enabled: boolean) {
|
|
175
|
+
this._enableTranslateExtent = enabled;
|
|
176
|
+
|
|
177
|
+
this.updateTranslateExtent();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Update translate extent (pan limits)
|
|
182
|
+
*/
|
|
183
|
+
updateTranslateExtent(): void {
|
|
184
|
+
const { width, xSpan, zFactor, enableTranslateExtent, translateBoundsX, translateBoundsY } = this;
|
|
185
|
+
|
|
186
|
+
let x1: number = -Infinity;
|
|
187
|
+
let y1: number = -Infinity;
|
|
188
|
+
let x2: number = +Infinity;
|
|
189
|
+
let y2: number = +Infinity;
|
|
190
|
+
|
|
191
|
+
if (enableTranslateExtent) {
|
|
192
|
+
const ppu: number = width / xSpan;
|
|
193
|
+
|
|
194
|
+
x1 = translateBoundsX[0] * ppu;
|
|
195
|
+
x2 = translateBoundsX[1] * ppu;
|
|
196
|
+
y1 = translateBoundsY[0] * ppu * zFactor;
|
|
197
|
+
y2 = translateBoundsY[1] * ppu * zFactor;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
this.zoom.translateExtent([
|
|
201
|
+
[x1, y1],
|
|
202
|
+
[x2, y2],
|
|
203
|
+
]);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Create an event object from current state
|
|
208
|
+
*/
|
|
209
|
+
currentStateAsEvent(): OnRescaleEvent {
|
|
210
|
+
const { scaleX, scaleY, xBounds, yBounds, zFactor, viewportRatio, currentTransform, xRatio, yRatio, width, height } = this;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
xScale: scaleX.copy(),
|
|
214
|
+
yScale: scaleY.copy(),
|
|
215
|
+
xBounds: xBounds,
|
|
216
|
+
yBounds: yBounds,
|
|
217
|
+
zFactor: zFactor,
|
|
218
|
+
viewportRatio,
|
|
219
|
+
xRatio: xRatio,
|
|
220
|
+
yRatio: yRatio,
|
|
221
|
+
width: width,
|
|
222
|
+
height: height,
|
|
223
|
+
transform: Object.assign({}, currentTransform),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Update scale
|
|
229
|
+
*/
|
|
230
|
+
rescale(): void {
|
|
231
|
+
const { currentStateAsEvent } = this;
|
|
232
|
+
|
|
233
|
+
this.onRescale(currentStateAsEvent());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Initialized handler
|
|
238
|
+
*/
|
|
239
|
+
init(): void {
|
|
240
|
+
this.zoom = zoom().scaleExtent([this.options.minZoomLevel, this.options.maxZoomLevel]).on('zoom', this.onZoom);
|
|
241
|
+
|
|
242
|
+
this.container.call(this.zoom);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Handle zoom
|
|
247
|
+
*/
|
|
248
|
+
onZoom(event: { transform: ZoomTransform }): void {
|
|
249
|
+
const { transform } = event;
|
|
250
|
+
if (!transform) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
this.applyTransform(transform);
|
|
255
|
+
this.rescale();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Update scale
|
|
260
|
+
*/
|
|
261
|
+
applyTransform(transform: ZoomTransform): void {
|
|
262
|
+
const { width, scaleX, scaleY, xSpan, xBounds, yBounds, zFactor } = this;
|
|
263
|
+
|
|
264
|
+
const { viewportRatio: ratio, isXInverted, isYInverted } = this;
|
|
265
|
+
|
|
266
|
+
const newWidth: number = width * transform.k;
|
|
267
|
+
|
|
268
|
+
const unitsPerPixels: number = xSpan / newWidth;
|
|
269
|
+
|
|
270
|
+
const newXSpan: number = xSpan / transform.k;
|
|
271
|
+
const newYSpan: number = newXSpan / zFactor / ratio;
|
|
272
|
+
|
|
273
|
+
const shiftx: number = unitsPerPixels * transform.x;
|
|
274
|
+
const shifty: number = (unitsPerPixels / zFactor) * transform.y;
|
|
275
|
+
const dx0: number = xBounds[0] - (isXInverted ? -shiftx : shiftx);
|
|
276
|
+
const dy0: number = yBounds[0] - (isYInverted ? -shifty : shifty);
|
|
277
|
+
|
|
278
|
+
scaleX.domain([dx0, dx0 + (isXInverted ? -newXSpan : newXSpan)]);
|
|
279
|
+
scaleY.domain([dy0, dy0 + (isYInverted ? -newYSpan : newYSpan)]);
|
|
280
|
+
|
|
281
|
+
this.currentTransform = transform;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Set new viewport
|
|
286
|
+
* @param cx - center X pos
|
|
287
|
+
* @param cy - center Y pos
|
|
288
|
+
* @param displ
|
|
289
|
+
* @param duration - duration of transition
|
|
290
|
+
* @returns a merge of filter and payload
|
|
291
|
+
*/
|
|
292
|
+
setViewport(cx?: number, cy?: number, displ?: number, duration?: number): void {
|
|
293
|
+
const { zoom, container, calculateTransform, scaleX, scaleY, isXInverted } = this;
|
|
294
|
+
|
|
295
|
+
if (isNaN(cx) || isNaN(displ)) {
|
|
296
|
+
const xd: number[] = scaleX.domain();
|
|
297
|
+
const dspan: number = xd[1] - xd[0];
|
|
298
|
+
if (isNaN(cx)) {
|
|
299
|
+
cx = xd[0] + dspan / 2 || 0;
|
|
300
|
+
}
|
|
301
|
+
if (isNaN(displ)) {
|
|
302
|
+
displ = Math.abs(dspan) || 1;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (isNaN(cy)) {
|
|
307
|
+
const yd: number[] = scaleY.domain();
|
|
308
|
+
cy = yd[0] + (yd[1] - yd[0]) / 2 || 0;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const xdispl: number = isXInverted ? -displ : displ;
|
|
312
|
+
|
|
313
|
+
const dx0: number = cx - xdispl / 2;
|
|
314
|
+
const dx1: number = dx0 + xdispl;
|
|
315
|
+
|
|
316
|
+
const t: ZoomTransform = calculateTransform(dx0, dx1, cy);
|
|
317
|
+
|
|
318
|
+
if (Number.isFinite(duration) && duration > 0) {
|
|
319
|
+
zoom.transform(container.transition().duration(duration), t);
|
|
320
|
+
} else {
|
|
321
|
+
zoom.transform(container, t);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Set bounds
|
|
327
|
+
*/
|
|
328
|
+
setBounds(xBounds: [number, number], yBounds: [number, number]): void {
|
|
329
|
+
this.xBounds = xBounds;
|
|
330
|
+
this.yBounds = yBounds;
|
|
331
|
+
|
|
332
|
+
this.recalculateZoomTransform();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Set bounds
|
|
337
|
+
*/
|
|
338
|
+
setTranslateBounds(xBounds: [number, number], yBounds: [number, number]): void {
|
|
339
|
+
this.translateBoundsX = xBounds;
|
|
340
|
+
this.translateBoundsY = yBounds;
|
|
341
|
+
|
|
342
|
+
this.updateTranslateExtent();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Adjust zoom due to changes in size of target
|
|
347
|
+
* @param force - force update even if size did not change
|
|
348
|
+
*/
|
|
349
|
+
adjustToSize(width?: number | boolean, height?: number, force: boolean = false): void {
|
|
350
|
+
const { width: oldWidth, height: oldHeight, scaleX, scaleY, recalculateZoomTransform } = this;
|
|
351
|
+
|
|
352
|
+
let w = 0;
|
|
353
|
+
let h = 0;
|
|
354
|
+
|
|
355
|
+
if (typeof width === 'undefined' || typeof width === 'boolean') {
|
|
356
|
+
const { width: containerWidth, height: containerHeight } = this.container.node().getBoundingClientRect();
|
|
357
|
+
w = containerWidth;
|
|
358
|
+
h = containerHeight;
|
|
359
|
+
} else {
|
|
360
|
+
w = width;
|
|
361
|
+
h = height;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const newWidth: number = Math.max(1, w);
|
|
365
|
+
const newHeight: number = Math.max(1, h);
|
|
366
|
+
|
|
367
|
+
// exit early if nothing has changed
|
|
368
|
+
if (!force && oldWidth === newWidth && oldHeight === newHeight) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
scaleX.range([0, newWidth]);
|
|
373
|
+
scaleY.range([0, newHeight]);
|
|
374
|
+
|
|
375
|
+
recalculateZoomTransform();
|
|
376
|
+
this.onRescale(this.currentStateAsEvent());
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Calculate new transform
|
|
381
|
+
* @param dx0
|
|
382
|
+
* @param dx1
|
|
383
|
+
* @param dy
|
|
384
|
+
* @returns New transformation matrix
|
|
385
|
+
*/
|
|
386
|
+
calculateTransform(dx0: number, dx1: number, dy: number): ZoomTransform {
|
|
387
|
+
const { scaleX, xSpan, xBounds, yBounds, zFactor, viewportRatio: ratio, isXInverted, isYInverted } = this;
|
|
388
|
+
|
|
389
|
+
const [rx1, rx2] = scaleX.range();
|
|
390
|
+
const displ: number = Math.abs(dx1 - dx0);
|
|
391
|
+
const k: number = xSpan / displ;
|
|
392
|
+
const unitsPerPixels: number = displ / (rx2 - rx1);
|
|
393
|
+
|
|
394
|
+
const dy0: number = dy - (isYInverted ? -displ : displ) / zFactor / ratio / 2;
|
|
395
|
+
|
|
396
|
+
const tx: number = (xBounds[0] - dx0) / (isXInverted ? -unitsPerPixels : unitsPerPixels);
|
|
397
|
+
const ty: number = (yBounds[0] - dy0) / ((isYInverted ? -unitsPerPixels : unitsPerPixels) / zFactor);
|
|
398
|
+
|
|
399
|
+
return zoomIdentity.translate(tx, ty).scale(k);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Recalcualate the transform
|
|
404
|
+
*/
|
|
405
|
+
recalculateZoomTransform(): void {
|
|
406
|
+
const { scaleX, scaleY, container, calculateTransform, updateTranslateExtent } = this;
|
|
407
|
+
|
|
408
|
+
const [dx0, dx1] = scaleX.domain();
|
|
409
|
+
const [dy0, dy1] = scaleY.domain();
|
|
410
|
+
|
|
411
|
+
const dy: number = dy0 + (dy1 - dy0) / 2;
|
|
412
|
+
|
|
413
|
+
const transform: ZoomTransform = calculateTransform(dx0, dx1, dy);
|
|
414
|
+
|
|
415
|
+
updateTranslateExtent();
|
|
416
|
+
|
|
417
|
+
this.zoom.transform(container, transform);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
setZoomLevelBoundary(zoomlevels: [number, number]): ZoomPanHandler {
|
|
421
|
+
this.zoom.scaleExtent(zoomlevels);
|
|
422
|
+
return this;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
setMaxZoomLevel(zoomlevel: number): ZoomPanHandler {
|
|
426
|
+
const zoomLevels = this.zoom.scaleExtent();
|
|
427
|
+
this.zoom.scaleExtent([zoomLevels[0], zoomlevel]);
|
|
428
|
+
return this;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
setMinZoomLevel(zoomlevel: number): ZoomPanHandler {
|
|
432
|
+
const zoomLevels = this.zoom.scaleExtent();
|
|
433
|
+
this.zoom.scaleExtent([zoomlevel, zoomLevels[1]]);
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IntersectionReferenceSystem } from './IntersectionReferenceSystem';
|
|
2
|
+
import { ScaleOptions } from '../interfaces';
|
|
3
|
+
import { Layer } from '../layers';
|
|
4
|
+
|
|
5
|
+
export interface AxisOptions {
|
|
6
|
+
xLabel: string;
|
|
7
|
+
yLabel: string;
|
|
8
|
+
unitOfMeasure: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ControllerOptions {
|
|
12
|
+
container: HTMLElement;
|
|
13
|
+
axisOptions?: AxisOptions;
|
|
14
|
+
scaleOptions?: ScaleOptions;
|
|
15
|
+
referenceSystem?: IntersectionReferenceSystem;
|
|
16
|
+
layers?: Layer<unknown>[];
|
|
17
|
+
path?: number[][];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface OverlayEvent<T> {
|
|
21
|
+
target?: Element;
|
|
22
|
+
source: Element;
|
|
23
|
+
caller: T;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface OverlayResizeEvent<T> extends OverlayEvent<T> {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface OverlayMouseMoveEvent<T> extends OverlayEvent<T> {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface OverlayMouseExitEvent<T> extends OverlayEvent<T> {}
|
|
37
|
+
|
|
38
|
+
export interface OverlayCallbacks<T> {
|
|
39
|
+
onMouseMove?(event: OverlayMouseMoveEvent<T>): void;
|
|
40
|
+
onMouseExit?(event: OverlayMouseExitEvent<T>): void;
|
|
41
|
+
onResize?(event: OverlayResizeEvent<T>): void;
|
|
42
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { select, Selection, pointer, ContainerElement } from 'd3-selection';
|
|
2
|
+
import { OverlayCallbacks } from './interfaces';
|
|
3
|
+
|
|
4
|
+
export class Overlay<T> {
|
|
5
|
+
elm: Selection<Element, unknown, null, undefined>;
|
|
6
|
+
source: Element;
|
|
7
|
+
elements: { [propName: string]: Element } = {};
|
|
8
|
+
listeners: { [propName: string]: OverlayCallbacks<T> } = {};
|
|
9
|
+
enabled = true;
|
|
10
|
+
|
|
11
|
+
constructor(caller: T, container: HTMLElement) {
|
|
12
|
+
const con = select(container);
|
|
13
|
+
this.elm = con.append('div').attr('id', 'overlay').style('z-index', '11').style('position', 'absolute');
|
|
14
|
+
|
|
15
|
+
this.source = this.elm.node();
|
|
16
|
+
|
|
17
|
+
const { elm } = this;
|
|
18
|
+
elm.on('resize', (event) => {
|
|
19
|
+
const { width, height } = event.detail;
|
|
20
|
+
elm.style('width', `${width}px`).style('height', `${height}px`);
|
|
21
|
+
|
|
22
|
+
if (!this.enabled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Object.keys(this.listeners).forEach((key: string) => {
|
|
27
|
+
const target = this.elements[key] || null;
|
|
28
|
+
const ops = this.listeners[key];
|
|
29
|
+
if (ops && ops.onResize) {
|
|
30
|
+
requestAnimationFrame(() =>
|
|
31
|
+
ops.onResize({
|
|
32
|
+
target,
|
|
33
|
+
source: this.source,
|
|
34
|
+
caller,
|
|
35
|
+
width,
|
|
36
|
+
height,
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
elm.on('mousemove', (event) => {
|
|
44
|
+
if (!this.enabled) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const [mx, my] = pointer(event, this.elm.node() as ContainerElement);
|
|
49
|
+
Object.keys(this.listeners).forEach((key: string) => {
|
|
50
|
+
const target = this.elements[key] || null;
|
|
51
|
+
const ops = this.listeners[key];
|
|
52
|
+
|
|
53
|
+
if (ops && ops.onMouseMove) {
|
|
54
|
+
requestAnimationFrame(() =>
|
|
55
|
+
ops.onMouseMove({
|
|
56
|
+
x: mx,
|
|
57
|
+
y: my,
|
|
58
|
+
target,
|
|
59
|
+
source: this.source,
|
|
60
|
+
caller,
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
elm.on('mouseout', () => {
|
|
68
|
+
if (!this.enabled) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
Object.keys(this.listeners).forEach((key: string) => {
|
|
72
|
+
const target = this.elements[key] || null;
|
|
73
|
+
const ops = this.listeners[key];
|
|
74
|
+
if (ops && ops.onMouseExit) {
|
|
75
|
+
requestAnimationFrame(() =>
|
|
76
|
+
ops.onMouseExit({
|
|
77
|
+
target,
|
|
78
|
+
source: this.source,
|
|
79
|
+
caller,
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
create(key: string, callbacks?: OverlayCallbacks<T>): HTMLElement {
|
|
88
|
+
const newElm = this.elm.append('div').style('position', 'relative').style('pointer-events', 'none').node();
|
|
89
|
+
this.elements[key] = newElm;
|
|
90
|
+
if (callbacks) {
|
|
91
|
+
this.listeners[key] = callbacks;
|
|
92
|
+
}
|
|
93
|
+
return newElm;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
register(key: string, callbacks: OverlayCallbacks<T>): void {
|
|
97
|
+
this.listeners[key] = callbacks;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
remove(key: string): void {
|
|
101
|
+
const el = this.elements[key];
|
|
102
|
+
if (el) {
|
|
103
|
+
select(el).remove();
|
|
104
|
+
delete this.elements[key];
|
|
105
|
+
}
|
|
106
|
+
delete this.listeners[key];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
setZIndex(zIndex: number): void {
|
|
110
|
+
this.elm.style('z-index', zIndex);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
destroy(): void {
|
|
114
|
+
this.source.remove();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const overlay = <T>(caller: T, container: HTMLElement): Overlay<T> => new Overlay<T>(caller, container);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { scaleLinear } from 'd3-scale';
|
|
2
|
+
import { color } from 'd3-color';
|
|
3
|
+
|
|
4
|
+
export function createColorTable(colorMap: string[], size: number): number[][] {
|
|
5
|
+
const colorDomain = colorMap.map((_v, i) => (i * size) / colorMap.length);
|
|
6
|
+
const colorScale = scaleLinear<string>().domain(colorDomain).range(colorMap);
|
|
7
|
+
|
|
8
|
+
const table = Array.from(new Array(size).keys()).map((i) => {
|
|
9
|
+
const rgb = color(colorScale(i)).rgb();
|
|
10
|
+
return [rgb.r, rgb.g, rgb.b];
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return table;
|
|
14
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function findIndexOfSample(data: number[][], pos: number): number {
|
|
2
|
+
let a = 0;
|
|
3
|
+
let b = data.length - 1;
|
|
4
|
+
const linearSearchLimit = 20;
|
|
5
|
+
let aPos = data[a][0];
|
|
6
|
+
let bPos = data[b][0];
|
|
7
|
+
|
|
8
|
+
while (b - a > linearSearchLimit) {
|
|
9
|
+
const splitAt = Math.floor((b + a) / 2);
|
|
10
|
+
const splitPos = data[splitAt][0];
|
|
11
|
+
|
|
12
|
+
if (pos >= aPos && pos < splitPos) {
|
|
13
|
+
b = splitAt;
|
|
14
|
+
bPos = data[b][0];
|
|
15
|
+
} else if (pos >= splitPos && pos <= bPos) {
|
|
16
|
+
a = splitAt;
|
|
17
|
+
aPos = data[a][0];
|
|
18
|
+
} else if (pos <= aPos && pos > splitPos) {
|
|
19
|
+
b = splitAt;
|
|
20
|
+
bPos = data[b][0];
|
|
21
|
+
} else if (pos <= splitPos && pos >= bPos) {
|
|
22
|
+
a = splitAt;
|
|
23
|
+
aPos = data[a][0];
|
|
24
|
+
} else {
|
|
25
|
+
return -1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let index = -1;
|
|
30
|
+
for (let i = a; i < b; i++) {
|
|
31
|
+
const v1 = data[i][0];
|
|
32
|
+
const v2 = data[i + 1][0];
|
|
33
|
+
if (Math.min(v1, v2) <= pos && pos <= Math.max(v1, v2)) {
|
|
34
|
+
index = i;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return index;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function findSampleAtPos(data: number[][], pos: number, topLimit: number = null, bottomLimit: number = null): number {
|
|
43
|
+
let y: number = null;
|
|
44
|
+
const index = findIndexOfSample(data, pos);
|
|
45
|
+
if (index !== -1) {
|
|
46
|
+
const v1 = data[index][1];
|
|
47
|
+
const v2 = data[index + 1][1];
|
|
48
|
+
if (v2 && v2) {
|
|
49
|
+
const x1 = data[index][0];
|
|
50
|
+
const x2 = data[index + 1][0];
|
|
51
|
+
const span = x2 - x1;
|
|
52
|
+
const d = pos - x1;
|
|
53
|
+
const f = d / span;
|
|
54
|
+
y = v1 * (1 - f) + v2 * f;
|
|
55
|
+
if (topLimit && topLimit > y) {
|
|
56
|
+
y = topLimit;
|
|
57
|
+
}
|
|
58
|
+
if (bottomLimit && bottomLimit < y) {
|
|
59
|
+
y = bottomLimit;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return y;
|
|
64
|
+
}
|