@webviz/well-log-viewer 0.0.1-alpha.1 → 0.0.1-alpha.3

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 (77) hide show
  1. package/dist/SyncLogViewer.js +3 -4
  2. package/dist/SyncLogViewer.js.map +1 -1
  3. package/dist/components/WellLogView.js +5 -5
  4. package/dist/components/WellLogView.js.map +1 -1
  5. package/dist/demo/example-data/welllog_template_2.json +167 -167
  6. package/dist/demo/example-data/wellpick_colors.json +1 -1
  7. package/dist/demo/example-data/wellpicks.json +179 -179
  8. package/package.json +32 -5
  9. package/dist/Intro.stories.mdx +0 -59
  10. package/dist/package.json +0 -21
  11. package/src/Intro.stories.mdx +0 -59
  12. package/src/MapAndWellLogViewer.stories.jsx +0 -147
  13. package/src/MapAndWellLogViewer.test.tsx +0 -26
  14. package/src/MapAndWellLogViewer.tsx +0 -473
  15. package/src/SyncLogViewer.stories.jsx +0 -361
  16. package/src/SyncLogViewer.test.tsx +0 -41
  17. package/src/SyncLogViewer.tsx +0 -1188
  18. package/src/WellLogViewer.png +0 -0
  19. package/src/WellLogViewer.stories.jsx +0 -169
  20. package/src/WellLogViewer.test.tsx +0 -53
  21. package/src/WellLogViewer.tsx +0 -439
  22. package/src/WellLogViewer_performance.test.tsx +0 -78
  23. package/src/__snapshots__/MapAndWellLogViewer.test.tsx.snap +0 -365
  24. package/src/__snapshots__/SyncLogViewer.test.tsx.snap +0 -510
  25. package/src/__snapshots__/WellLogViewer.test.tsx.snap +0 -552
  26. package/src/components/AxisSelector.test.tsx +0 -50
  27. package/src/components/AxisSelector.tsx +0 -49
  28. package/src/components/ColorTableTypes.ts +0 -9
  29. package/src/components/InfoPanel.test.tsx +0 -58
  30. package/src/components/InfoPanel.tsx +0 -144
  31. package/src/components/InfoTypes.ts +0 -17
  32. package/src/components/LocalMenus.tsx +0 -336
  33. package/src/components/PlotDialog.tsx +0 -419
  34. package/src/components/Scroller.stories.jsx +0 -80
  35. package/src/components/Scroller.test.tsx +0 -22
  36. package/src/components/Scroller.tsx +0 -173
  37. package/src/components/TrackDialog.tsx +0 -217
  38. package/src/components/WellLogSpacer.tsx +0 -483
  39. package/src/components/WellLogTemplateTypes.ts +0 -65
  40. package/src/components/WellLogTypes.ts +0 -53
  41. package/src/components/WellLogView.stories.jsx +0 -84
  42. package/src/components/WellLogView.test.tsx +0 -52
  43. package/src/components/WellLogView.tsx +0 -2063
  44. package/src/components/WellLogViewWithScroller.stories.jsx +0 -69
  45. package/src/components/WellLogViewWithScroller.test.tsx +0 -47
  46. package/src/components/WellLogViewWithScroller.tsx +0 -179
  47. package/src/components/ZoomSlider.stories.jsx +0 -52
  48. package/src/components/ZoomSlider.test.tsx +0 -28
  49. package/src/components/ZoomSlider.tsx +0 -86
  50. package/src/components/__snapshots__/AxisSelector.test.tsx.snap +0 -28
  51. package/src/components/__snapshots__/InfoPanel.test.tsx.snap +0 -103
  52. package/src/components/__snapshots__/Scroller.test.tsx.snap +0 -13
  53. package/src/components/__snapshots__/WellLogView.test.tsx.snap +0 -54
  54. package/src/components/__snapshots__/WellLogViewWithScroller.test.tsx.snap +0 -270
  55. package/src/components/__snapshots__/ZoomSlider.test.tsx.snap +0 -50
  56. package/src/components/styles.scss +0 -106
  57. package/src/custom.d.ts +0 -13
  58. package/src/demo/example-data/volve_logs.json +0 -689617
  59. package/src/demo/example-data/welllog_template_2.json +0 -196
  60. package/src/demo/example-data/wellpick_colors.json +0 -156
  61. package/src/demo/example-data/wellpicks.json +0 -186
  62. package/src/index.ts +0 -8
  63. package/src/utils/axes.ts +0 -26
  64. package/src/utils/color-table.ts +0 -153
  65. package/src/utils/deepcopy.ts +0 -3
  66. package/src/utils/edit-track.tsx +0 -40
  67. package/src/utils/fill-info.ts +0 -224
  68. package/src/utils/gradientfill-plot-legend.ts +0 -177
  69. package/src/utils/gradientfill-plot.ts +0 -203
  70. package/src/utils/graph/factory.ts +0 -15
  71. package/src/utils/legend/common.ts +0 -153
  72. package/src/utils/log-viewer.ts +0 -209
  73. package/src/utils/minmax.ts +0 -126
  74. package/src/utils/pattern.tsx +0 -50
  75. package/src/utils/stack/stack-legend.ts +0 -100
  76. package/src/utils/tracks.ts +0 -1559
  77. package/tsconfig.json +0 -8
@@ -1,1188 +0,0 @@
1
- import React, { Component, ReactNode } from "react";
2
-
3
- import PropTypes from "prop-types";
4
-
5
- import WellLogSpacer from "./components/WellLogSpacer";
6
- import WellLogViewWithScroller from "./components/WellLogViewWithScroller";
7
- import InfoPanel from "./components/InfoPanel";
8
- import AxisSelector from "./components/AxisSelector";
9
-
10
- import ZoomSlider from "./components/ZoomSlider";
11
-
12
- import { WellLog } from "./components/WellLogTypes";
13
- import { Template } from "./components/WellLogTemplateTypes";
14
- import { ColorTable } from "./components/ColorTableTypes";
15
- import { PatternsTable } from "./utils/pattern";
16
-
17
- import { WellLogController, WellPickProps } from "./components/WellLogView";
18
-
19
- import WellLogView from "./components/WellLogView";
20
- import { WellLogViewOptions } from "./components/WellLogView";
21
- import { WellLogSpacerOptions } from "./components/WellLogSpacer";
22
- import { getWellPicks } from "./components/WellLogView";
23
-
24
- import { getAvailableAxes } from "./utils/tracks";
25
-
26
- import { checkMinMax } from "./utils/minmax";
27
- function isEqDomains(d1: [number, number], d2: [number, number]): boolean {
28
- const eps: number = Math.abs(d1[1] - d1[0] + (d2[1] - d2[0])) * 0.00001;
29
- return Math.abs(d1[0] - d2[0]) < eps && Math.abs(d1[1] - d2[1]) < eps;
30
- }
31
-
32
- import { onTrackMouseEvent } from "./utils/edit-track";
33
- import { fillInfos } from "./utils/fill-info";
34
- import { LogViewer } from "@equinor/videx-wellog";
35
-
36
- import { Info, InfoOptions } from "./components/InfoTypes";
37
-
38
- import { isEqualRanges } from "./components/WellLogView";
39
- //import { boolean } from "mathjs";
40
-
41
- export function isEqualArrays(
42
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
- d1: undefined | any[],
44
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
- d2: undefined | any[]
46
- ): boolean {
47
- if (!d1) return !d2;
48
- if (!d2) return !d1;
49
-
50
- const n = d1.length;
51
- if (n !== d2.length) return false;
52
-
53
- for (let i = 0; i < n; i++) {
54
- if (d1[i] !== d2[i]) return false;
55
- }
56
- return true;
57
- }
58
-
59
- interface Props {
60
- /**
61
- * Object from JSON file describing single well log data.
62
- */
63
- welllogs: WellLog[];
64
-
65
- /**
66
- * Prop containing track templates data.
67
- */
68
- templates: Template[];
69
- /**
70
- * Prop containing color table data.
71
- */
72
- colorTables: ColorTable[];
73
- /**
74
- * Set to true for default titles or to array of individial welllog titles
75
- */
76
- viewTitles?: boolean | (boolean | string | JSX.Element)[];
77
-
78
- /**
79
- * Well Picks data array
80
- */
81
- wellpicks?: WellPickProps[];
82
-
83
- /**
84
- * Patterns table
85
- */
86
- patternsTable?: PatternsTable;
87
- /**
88
- * Horizon to pattern index map
89
- */
90
- patterns?: [string, number][];
91
-
92
- /**
93
- * Horizon names for wellpick flatting (pan and zoom)
94
- */
95
- wellpickFlatting?: string[]; // For example ["Hor_5", "Hor_3"];
96
-
97
- /**
98
- * Set to true or to spacer width or to array of widths if WellLogSpacers should be used
99
- */
100
- spacers?: boolean | number | number[];
101
- /**
102
- * Distanses between wells to show on the spacers
103
- */
104
- wellDistances?: {
105
- units: string;
106
- distances: (number | undefined)[];
107
- };
108
-
109
- /**
110
- * Orientation of the track plots on the screen.
111
- */
112
- horizontal?: boolean;
113
- syncTrackPos?: boolean;
114
- syncContentDomain?: boolean;
115
- syncContentSelection?: boolean;
116
- syncTemplate?: boolean;
117
-
118
- /**
119
- * Primary axis id: "md", "tvd", "time"... Default is the first available from axisMnemos
120
- */
121
- primaryAxis?: string;
122
-
123
- /**
124
- * Log mnemonics for axes
125
- */
126
- axisTitles: Record<string, string>;
127
-
128
- /**
129
- * Names for axes
130
- */
131
- axisMnemos: Record<string, string[]>;
132
-
133
- /**
134
- * Initial visible range
135
- */
136
- domain?: [number, number];
137
-
138
- /**
139
- * Initial selected range
140
- */
141
- selection?: [number | undefined, number | undefined];
142
-
143
- /**
144
- * Options for well log views
145
- */
146
- welllogOptions?: WellLogViewOptions;
147
- /**
148
- * Options for well log spacers
149
- */
150
- spacerOptions?: WellLogSpacerOptions;
151
- /**
152
- * Options for readout
153
- */
154
- readoutOptions?: InfoOptions; // options for readout
155
-
156
- // callbacks
157
- onContentRescale?: (iView: number) => void;
158
- onContentSelection?: (iView: number) => void;
159
- onTemplateChanged?: (iView: number) => void;
160
-
161
- onCreateController?: (iView: number, controller: WellLogController) => void;
162
- }
163
-
164
- export const argTypesSyncLogViewerProp = {
165
- id: {
166
- description:
167
- "The ID of this component, used to identify dash components in callbacks. The ID needs to be unique across all of the components in an app.",
168
- },
169
- welllogs: {
170
- description: "Array of JSON objects describing well log data.",
171
- },
172
- templates: {
173
- description: "Array of track template data.",
174
- },
175
- colorTables: {
176
- description: "Prop containing color table data.",
177
- },
178
- wellpicks: {
179
- description: "Well Picks data array",
180
- },
181
- patternsTable: {
182
- description: "Patterns table",
183
- },
184
- patterns: {
185
- description: "Horizon to pattern index map",
186
- },
187
-
188
- spacers: {
189
- description:
190
- "Set to true or spacer width or to array of widths if WellLogSpacers should be used",
191
- },
192
- wellDistances: {
193
- description: "Distanses between wells to show on the spacers",
194
- },
195
-
196
- horizontal: {
197
- description: "Orientation of the track plots on the screen.",
198
- },
199
- syncTrackPos: {
200
- description: "Synchronize first visible track", // defaultValue: false
201
- },
202
- syncContentDomain: {
203
- description: "Synchronize visible content domain (pan and zoom)", // defaultValue: false
204
- },
205
- syncContentSelection: {
206
- description: "Synchronize content selection", // defaultValue: false
207
- },
208
- syncTemplate: {
209
- description: "Synchronize templates in the views", // defaultValue: false
210
- },
211
- welllogOptions: {
212
- description:
213
- "Options for well log views:<br/>" +
214
- "maxContentZoom: The maximum zoom value (default 256)<br/>" +
215
- "maxVisibleTrackNum: The maximum number of visible tracks<br/>" +
216
- "checkDatafileSchema: Validate JSON datafile against schema<br/>" +
217
- "hideTrackTitle: Hide titles on the tracks<br/>" +
218
- "hideLegend: Hide legends on the tracks.",
219
- },
220
- readoutOptions: {
221
- description:
222
- "Options for readout panel.<br/>" +
223
- "allTracks: boolean — Show not only visible tracks,<br/>" +
224
- "grouping: string — How group values.",
225
- //defaultValue: {
226
- // allTracks: false,
227
- // grouping: "by_track",
228
- //},
229
- },
230
- domain: {
231
- description: "Initial visible interval of the log data.",
232
- },
233
- selection: {
234
- description: "Initial selected interval of the log data.",
235
- },
236
- viewTitles: {
237
- description:
238
- "Set to true for default titles or to array of individial welllog titles",
239
- },
240
- // callbacks...
241
- };
242
-
243
- interface State {
244
- axes: string[]; // axes available in welllog
245
- primaryAxis: string;
246
- infos: Info[][];
247
-
248
- sliderValue: number; // value for zoom slider
249
- }
250
-
251
- class SyncLogViewer extends Component<Props, State> {
252
- public static propTypes: Record<string, unknown>;
253
-
254
- controllers: (WellLogController | null)[];
255
- spacers: (WellLogSpacer | null)[];
256
-
257
- collapsedTrackIds: (string | number)[];
258
-
259
- callbacks: {
260
- onCreateControllerBind: (controller: WellLogController) => void;
261
- onInfoBind: (
262
- x: number,
263
- logController: LogViewer,
264
- iFrom: number,
265
- iTo: number
266
- ) => void;
267
- onTrackScrollBind: () => void;
268
- onTrackSelectionBind: () => void;
269
- onContentRescaleBind: () => void;
270
- onContentSelectionBind: () => void;
271
- onTemplateChangedBind: () => void;
272
- }[];
273
-
274
- constructor(props: Props) {
275
- super(props);
276
-
277
- const _axes = this.props.welllogs.map((welllog: WellLog) =>
278
- getAvailableAxes(welllog, this.props.axisMnemos)
279
- );
280
- const axes = _axes[0];
281
- let primaryAxis = axes?.[0];
282
- if (this.props.templates[0] && axes) {
283
- this.props.templates[0].scale.primary = "tvd"; //!!!!!
284
- if (
285
- this.props.templates[0] &&
286
- this.props.templates[0].scale.primary
287
- ) {
288
- if (axes.indexOf(this.props.templates[0].scale.primary) >= 0)
289
- primaryAxis = this.props.templates[0].scale.primary;
290
- }
291
- }
292
- if (this.props.primaryAxis) primaryAxis = this.props.primaryAxis;
293
- this.state = {
294
- primaryAxis: primaryAxis, //"md"
295
- axes: axes, //["md", "tvd"]
296
- infos: [[], []],
297
-
298
- sliderValue: 4.0, // zoom
299
- };
300
-
301
- this.controllers = [null, null];
302
- this.spacers = [null, null];
303
-
304
- this.collapsedTrackIds = [];
305
-
306
- this.onChangePrimaryAxis = this.onChangePrimaryAxis.bind(this);
307
-
308
- this.callbacks = [];
309
- this.props.welllogs.map((_welllog: WellLog, index: number) => {
310
- this.callbacks.push({
311
- onCreateControllerBind: this.onCreateController.bind(
312
- this,
313
- index
314
- ),
315
- onInfoBind: this.onInfo.bind(this, index),
316
- onTrackScrollBind: this.onTrackScroll.bind(this, index),
317
- onTrackSelectionBind: this.onTrackSelection.bind(this, index),
318
- onContentRescaleBind: this.onContentRescale.bind(this, index),
319
- onContentSelectionBind: this.onContentSelection.bind(
320
- this,
321
- index
322
- ),
323
- onTemplateChangedBind: this.onTemplateChanged.bind(this, index),
324
- });
325
- });
326
-
327
- this.onZoomSliderChange = this.onZoomSliderChange.bind(this);
328
-
329
- this.onInfoGroupClick = this.onInfoGroupClick.bind(this);
330
- }
331
-
332
- componentDidMount(): void {
333
- this.syncTrackScrollPos(0);
334
- this.syncContentScrollPos(0);
335
- this.syncContentSelection(0);
336
- this.setSliderValue();
337
- }
338
-
339
- shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
340
- //?!
341
- const ret =
342
- !Object.is(this.props, nextProps) ||
343
- !Object.is(this.state, nextState);
344
- return ret;
345
- }
346
-
347
- componentDidUpdate(prevProps: Props /*, prevState: State*/): void {
348
- if (
349
- this.props.welllogs !== prevProps.welllogs ||
350
- this.props.templates !== prevProps.templates ||
351
- this.props.axisMnemos !== prevProps.axisMnemos ||
352
- this.props.primaryAxis !== prevProps.primaryAxis /*||
353
- this.props.colorTables !== prevProps.colorTables*/
354
- ) {
355
- const _axes = this.props.welllogs.map((welllog) =>
356
- getAvailableAxes(welllog, this.props.axisMnemos)
357
- );
358
- const axes = _axes[0];
359
- let primaryAxis = axes[0];
360
- if (this.props.templates[0]) {
361
- this.props.templates[0].scale.primary = "tvd"; //!!!!!
362
- if (this.props.templates[0].scale.primary) {
363
- if (
364
- axes.indexOf(this.props.templates[0].scale.primary) < 0
365
- ) {
366
- if (this.props.welllogs === prevProps.welllogs) return; // nothing to update
367
- } else {
368
- primaryAxis = this.props.templates[0].scale.primary;
369
- }
370
- }
371
- }
372
- if (this.props.primaryAxis) primaryAxis = this.props.primaryAxis;
373
- this.setState({
374
- primaryAxis: primaryAxis,
375
- axes: axes,
376
- // will be changed by callback! infos: [],
377
- });
378
- }
379
-
380
- if (isEqualRanges(this.props.domain, prevProps.domain)) {
381
- this.setControllersZoom();
382
- }
383
-
384
- if (
385
- this.props.wellpicks !== prevProps.wellpicks ||
386
- !isEqualArrays(
387
- this.props.wellpickFlatting,
388
- prevProps.wellpickFlatting
389
- )
390
- ) {
391
- this.syncContentScrollPos(0); // force to redraw
392
- }
393
-
394
- if (isEqualRanges(this.props.selection, prevProps.selection)) {
395
- this.setControllersSelection();
396
- }
397
-
398
- if (
399
- this.props.syncContentSelection !== prevProps.syncContentSelection
400
- ) {
401
- this.syncContentSelection(0); // force to redraw selection
402
- }
403
-
404
- if (
405
- this.props.readoutOptions &&
406
- (!prevProps.readoutOptions ||
407
- this.props.readoutOptions.allTracks !==
408
- prevProps.readoutOptions.allTracks ||
409
- this.props.readoutOptions.grouping !==
410
- prevProps.readoutOptions.grouping)
411
- ) {
412
- this.updateReadoutPanel();
413
- }
414
- }
415
-
416
- updateReadoutPanel(): void {
417
- for (const controller of this.controllers) {
418
- if (!controller) continue;
419
- controller.selectContent(controller.getContentSelection()); // force to update readout panel
420
- }
421
- }
422
-
423
- // callback function from WellLogView
424
- onInfo(
425
- iView: number,
426
- x: number,
427
- logController: LogViewer,
428
- iFrom: number,
429
- iTo: number
430
- ): void {
431
- const infos = fillInfos(
432
- x,
433
- logController,
434
- iFrom,
435
- iTo,
436
- this.collapsedTrackIds,
437
- this.props.readoutOptions
438
- );
439
-
440
- this.setState((state: Readonly<State>) => {
441
- const newState: { infos: Info[][] } = { infos: [] };
442
- this.props.welllogs.map((_welllog: WellLog, index: number) =>
443
- newState.infos.push(iView == index ? infos : state.infos[index])
444
- );
445
- return newState;
446
- });
447
- }
448
- // callback function from WellLogView
449
- onCreateController(iView: number, controller: WellLogController): void {
450
- this.controllers[iView] = controller;
451
- if (this.props.onCreateController)
452
- // set callback to component's caller
453
- this.props.onCreateController(iView, controller);
454
-
455
- this.setControllersZoom();
456
- this.syncTrackScrollPos(iView);
457
- this.syncContentScrollPos(iView);
458
- this.syncContentSelection(iView);
459
- }
460
- // callback function from WellLogView
461
- onTrackScroll(iView: number): void {
462
- this.syncTrackScrollPos(iView);
463
- }
464
- // callback function from WellLogView
465
- onTrackSelection(iView: number): void {
466
- this.syncTrackSelection(iView);
467
- }
468
- // callback function from WellLogView
469
- onContentRescale(iView: number): void {
470
- this.syncTrackScrollPos(iView);
471
- this.syncContentScrollPos(iView);
472
- this.syncContentSelection(iView);
473
-
474
- this.setSliderValue();
475
- if (this.props.onContentRescale) this.props.onContentRescale(iView);
476
- }
477
- // callback function from WellLogView
478
- onContentSelection(iView: number): void {
479
- this.syncContentSelection(iView);
480
- if (this.props.onContentSelection) this.props.onContentSelection(iView);
481
- }
482
- // callback function from WellLogView
483
- onTemplateChanged(iView: number): void {
484
- this.syncTemplate(iView);
485
-
486
- if (this.props.onTemplateChanged) {
487
- if (this.props.onTemplateChanged)
488
- this.props.onTemplateChanged(iView);
489
- }
490
- }
491
- // callback function from Axis selector
492
- onChangePrimaryAxis(value: string): void {
493
- this.setState({ primaryAxis: value });
494
- }
495
- // callback function from Zoom slider
496
- onZoomSliderChange(value: number): void {
497
- const iView = 0; // master
498
- const controller = this.controllers[iView];
499
- if (!controller) return;
500
- controller.zoomContent(value);
501
- this.syncContentScrollPos(iView);
502
- }
503
- // callback function from Scroller
504
- onScrollerScroll(iView: number, x: number, y: number): void {
505
- const controller = this.controllers[iView];
506
- if (!controller) return;
507
-
508
- const posMax = controller.getTrackScrollPosMax();
509
- let posTrack = (this.props.horizontal ? y : x) * posMax;
510
- posTrack = Math.round(posTrack);
511
- controller.scrollTrackTo(posTrack);
512
-
513
- const fContent = this.props.horizontal ? x : y; // fraction
514
- controller.scrollContentTo(fContent);
515
-
516
- const domain = controller.getContentDomain();
517
- for (const _controller of this.controllers) {
518
- if (!_controller || _controller == controller) continue;
519
- if (
520
- !(this.props.wellpickFlatting && this.props.wellpicks) &&
521
- this.props.syncContentDomain
522
- ) {
523
- const _domain = _controller.getContentDomain();
524
- if (!isEqDomains(_domain, domain))
525
- _controller.zoomContentTo(domain);
526
- }
527
- if (this.props.syncTrackPos) _controller.scrollTrackTo(posTrack);
528
- }
529
- }
530
-
531
- // set zoom value to slider
532
- setSliderValue(): void {
533
- this.setState((state: Readonly<State>) => {
534
- if (!this.controllers[0]) return null;
535
- const zoom = this.controllers[0].getContentZoom();
536
- if (Math.abs(Math.log(state.sliderValue / zoom)) < 0.01)
537
- return null;
538
- return { sliderValue: zoom };
539
- });
540
- }
541
-
542
- syncTrackScrollPos(iView: number): void {
543
- const controller = this.controllers[iView];
544
- if (!controller) return;
545
- const trackPos = controller.getTrackScrollPos();
546
- for (const _controller of this.controllers) {
547
- if (!_controller || _controller == controller) continue;
548
- if (this.props.syncTrackPos) _controller.scrollTrackTo(trackPos);
549
- }
550
- }
551
- syncTrackSelection(iView: number): void {
552
- const controller = this.controllers[iView];
553
- if (!controller) return;
554
- const trackSelection = controller.getSelectedTrackIndices();
555
- for (const _controller of this.controllers) {
556
- if (!_controller || _controller == controller) continue;
557
- if (this.props.syncTemplate)
558
- _controller.setSelectedTrackIndices(trackSelection);
559
- }
560
- }
561
-
562
- getCommonContentBaseDomain(): [number, number] {
563
- const commonBaseDomain: [number, number] = [
564
- Number.POSITIVE_INFINITY,
565
- Number.NEGATIVE_INFINITY,
566
- ];
567
- for (const controller of this.controllers) {
568
- if (!controller) continue;
569
- checkMinMax(commonBaseDomain, controller.getContentBaseDomain());
570
- }
571
- return commonBaseDomain;
572
- }
573
-
574
- syncContentBaseDomain(): boolean {
575
- let updated = false;
576
- if (
577
- !(this.props.wellpickFlatting && this.props.wellpicks) &&
578
- this.props.syncContentDomain
579
- ) {
580
- const commonBaseDomain: [number, number] =
581
- this.getCommonContentBaseDomain();
582
- for (const controller of this.controllers) {
583
- if (!controller) continue;
584
- const baseDomain = controller.getContentBaseDomain();
585
- if (!isEqDomains(baseDomain, commonBaseDomain)) {
586
- controller.setContentBaseDomain(commonBaseDomain);
587
- updated = true;
588
- }
589
- }
590
- }
591
- return updated;
592
- }
593
-
594
- makeFlattingCoeffs(): {
595
- A: number[][];
596
- B: number[][];
597
- newBaseDomain: [number, number][]; // not used
598
- } {
599
- const wellpickFlatting = this.props.wellpickFlatting;
600
- if (!wellpickFlatting) return { A: [], B: [], newBaseDomain: [] };
601
-
602
- const flattingA: number[][] = [];
603
- const flattingB: number[][] = [];
604
-
605
- const nView = this.controllers.length;
606
- const newBaseDomain: [number, number][] = [];
607
- for (let i = 0; i < nView; i++) {
608
- newBaseDomain.push([
609
- Number.POSITIVE_INFINITY,
610
- Number.NEGATIVE_INFINITY,
611
- ]);
612
- }
613
- for (const controller of this.controllers) {
614
- const wellLogView = controller as WellLogView;
615
- const wps = wellLogView ? getWellPicks(wellLogView) : [];
616
- let wp1: number | undefined = undefined;
617
- let wp2: number | undefined = undefined;
618
- for (const wp of wps) {
619
- if (wellpickFlatting[0] === wp.horizon) wp1 = wp.vPrimary;
620
- if (wellpickFlatting[1] === wp.horizon) wp2 = wp.vPrimary;
621
- }
622
-
623
- const _flattingA: number[] = [];
624
- const _flattingB: number[] = [];
625
- let j = -1;
626
- for (const _controller of this.controllers) {
627
- j++;
628
- if (!_controller || !controller) {
629
- _flattingA.push(0.0);
630
- _flattingB.push(0.0);
631
- continue;
632
- }
633
- const _wellLogView = _controller as WellLogView;
634
- const _wps = getWellPicks(_wellLogView);
635
- let _wp1: number | undefined = undefined;
636
- let _wp2: number | undefined = undefined;
637
- for (const _wp of _wps) {
638
- if (wellpickFlatting[0] === _wp.horizon)
639
- _wp1 = _wp.vPrimary;
640
- if (wellpickFlatting[1] === _wp.horizon)
641
- _wp2 = _wp.vPrimary;
642
- }
643
-
644
- if (
645
- Number.isFinite(wp1) &&
646
- Number.isFinite(_wp1) &&
647
- wp1 !== undefined &&
648
- _wp1 !== undefined
649
- ) {
650
- let a: number;
651
- if (
652
- Number.isFinite(wp2) &&
653
- Number.isFinite(_wp2) &&
654
- wp2 !== undefined &&
655
- _wp2 !== undefined &&
656
- wp2 - wp1
657
- )
658
- a = (_wp2 - _wp1) / (wp2 - wp1);
659
- else {
660
- if (this.props.syncContentDomain) {
661
- a = 1;
662
- } else {
663
- const domain = controller.getContentDomain();
664
- const _domain = _controller.getContentDomain();
665
- if (
666
- _domain[1] - _domain[0] &&
667
- domain[1] - domain[0]
668
- )
669
- a =
670
- (_domain[1] - _domain[0]) /
671
- (domain[1] - domain[0]);
672
- else a = 1;
673
- }
674
- }
675
- const b = _wp1 - a * wp1;
676
- _flattingA.push(a);
677
- _flattingB.push(b);
678
-
679
- const baseDomain = controller.getContentBaseDomain();
680
- const baseDomainNew: [number, number] = [
681
- a * baseDomain[0] + b,
682
- a * baseDomain[1] + b,
683
- ];
684
-
685
- checkMinMax(newBaseDomain[j], baseDomainNew);
686
- } else {
687
- // The first well pick undefined
688
- _flattingA.push(controller === _controller ? 1.0 : 0.0);
689
- _flattingB.push(0.0);
690
- }
691
- }
692
- flattingA.push(_flattingA);
693
- flattingB.push(_flattingB);
694
- }
695
-
696
- return { A: flattingA, B: flattingB, newBaseDomain: newBaseDomain };
697
- }
698
-
699
- syncContentScrollPos(iView: number): void {
700
- const controller = this.controllers[iView];
701
- if (!controller) return;
702
-
703
- let updated = false;
704
- const wellpickFlatting = this.props.wellpickFlatting;
705
- const syncContentDomain = this.props.syncContentDomain;
706
- let coeff: {
707
- A: number[][];
708
- B: number[][];
709
- newBaseDomain: [number, number][];
710
- } | null = null;
711
- if (this.props.wellpicks && wellpickFlatting) {
712
- coeff = this.makeFlattingCoeffs();
713
- }
714
- // synchronize base domains
715
- updated = this.syncContentBaseDomain();
716
- const domain = controller.getContentDomain();
717
-
718
- let j = -1;
719
- for (const _controller of this.controllers) {
720
- j++;
721
- if (!_controller || _controller == controller) continue;
722
- if (coeff) {
723
- // wellpick flatting
724
- const a = coeff.A[iView][j];
725
- const b = coeff.B[iView][j];
726
-
727
- const domainNew: [number, number] = [
728
- a * domain[0] + b,
729
- a * domain[1] + b,
730
- ];
731
- const _domain = _controller.getContentDomain();
732
- if (
733
- Number.isFinite(domainNew[0]) &&
734
- Number.isFinite(domainNew[1])
735
- ) {
736
- if (!isEqDomains(_domain, domainNew)) {
737
- _controller.zoomContentTo(domainNew);
738
- updated = true;
739
- }
740
-
741
- // sync scroll bar: not work yet
742
- const baseDomain = _controller.getContentBaseDomain();
743
- //const newBaseDomain = coeff.newBaseDomain[j];
744
- const newBaseDomain: [number, number] = [
745
- domainNew[0],
746
- domainNew[1],
747
- ];
748
- if (baseDomain[0] < newBaseDomain[0])
749
- newBaseDomain[0] = baseDomain[0];
750
- if (baseDomain[1] > newBaseDomain[1])
751
- newBaseDomain[1] = baseDomain[1];
752
- if (
753
- Number.isFinite(newBaseDomain[0]) &&
754
- Number.isFinite(newBaseDomain[1])
755
- )
756
- if (!isEqDomains(baseDomain, newBaseDomain)) {
757
- //_controller.setContentBaseDomain(newBaseDomain);
758
- //updated = true;
759
- }
760
- }
761
- } else if (syncContentDomain) {
762
- const _domain = _controller.getContentDomain();
763
- if (!isEqDomains(_domain, domain)) {
764
- _controller.zoomContentTo(domain);
765
- updated = true;
766
- }
767
- }
768
- }
769
-
770
- if (updated) {
771
- for (let i = iView - 1; i <= iView; i++) {
772
- const spacer = this.spacers[i];
773
- if (!spacer) continue;
774
- spacer.update();
775
- }
776
- }
777
- }
778
-
779
- syncContentSelection(iView: number): void {
780
- const controller = this.controllers[iView];
781
- if (!controller) return;
782
- const selection = controller.getContentSelection();
783
- for (const _controller of this.controllers) {
784
- if (!_controller || _controller == controller) continue;
785
- if (this.props.syncContentSelection) {
786
- const _selection = _controller.getContentSelection();
787
- if (!isEqualRanges(_selection, selection))
788
- _controller.selectContent(selection);
789
- }
790
- }
791
-
792
- for (const spacer of this.spacers) {
793
- if (!spacer) continue;
794
- spacer.forceUpdate();
795
- }
796
- }
797
-
798
- syncTemplate(iView: number): void {
799
- const controller = this.controllers[iView];
800
- if (!controller) return;
801
- const template = controller.getTemplate();
802
- for (const _controller of this.controllers) {
803
- if (!_controller || _controller == controller) continue;
804
- if (this.props.syncTemplate) _controller.setTemplate(template);
805
- }
806
- }
807
-
808
- setControllersZoom(): void {
809
- for (const controller of this.controllers) {
810
- if (!controller) continue;
811
- if (this.props.domain) controller.zoomContentTo(this.props.domain);
812
- }
813
- }
814
- setControllersSelection(): void {
815
- if (!this.props.selection) return;
816
- for (const controller of this.controllers) {
817
- if (!controller) continue;
818
- controller.selectContent(this.props.selection);
819
- }
820
- for (const spacer of this.spacers) {
821
- if (!spacer) continue;
822
- spacer.forceUpdate();
823
- }
824
- }
825
- onInfoGroupClick(trackId: string | number): void {
826
- const i = this.collapsedTrackIds.indexOf(trackId);
827
- if (i < 0) this.collapsedTrackIds.push(trackId);
828
- else delete this.collapsedTrackIds[i];
829
-
830
- this.updateReadoutPanel();
831
- }
832
-
833
- createView(index: number): ReactNode {
834
- const callbacks = this.callbacks[index];
835
- const wellLog = this.props.welllogs[index];
836
- const templates = this.props.templates;
837
- const template = templates[index] ? templates[index] : templates[0];
838
- const viewTitles = this.props.viewTitles;
839
- const viewTitle =
840
- viewTitles && (viewTitles === true ? true : viewTitles[index]);
841
- const options = {
842
- ...this.props.welllogOptions,
843
- maxVisibleTrackNum:
844
- this.props.welllogOptions?.maxVisibleTrackNum ||
845
- (this.props.horizontal ? 2 : 3),
846
- };
847
- return (
848
- <WellLogViewWithScroller
849
- key={index}
850
- welllog={wellLog}
851
- viewTitle={viewTitle}
852
- template={template}
853
- colorTables={this.props.colorTables}
854
- wellpick={this.props.wellpicks?.[index]}
855
- patternsTable={this.props.patternsTable}
856
- patterns={this.props.patterns}
857
- horizontal={this.props.horizontal}
858
- axisTitles={this.props.axisTitles}
859
- axisMnemos={this.props.axisMnemos}
860
- primaryAxis={this.state.primaryAxis}
861
- options={options}
862
- onInfo={callbacks.onInfoBind}
863
- onCreateController={callbacks.onCreateControllerBind}
864
- onTrackMouseEvent={onTrackMouseEvent}
865
- onTrackScroll={callbacks.onTrackScrollBind}
866
- onTrackSelection={callbacks.onTrackSelectionBind}
867
- onContentRescale={callbacks.onContentRescaleBind}
868
- onContentSelection={callbacks.onContentSelectionBind}
869
- onTemplateChanged={callbacks.onTemplateChangedBind}
870
- />
871
- );
872
- }
873
-
874
- createSpacer(index: number): ReactNode {
875
- if (!this.props.spacers) return null;
876
- const prev = index - 1;
877
-
878
- let width = 255;
879
- if (typeof this.props.spacers !== "boolean") {
880
- width =
881
- typeof this.props.spacers === "number"
882
- ? this.props.spacers // all widths are equal
883
- : this.props.spacers[prev]; // individual width
884
- }
885
-
886
- if (width === undefined) width = 255; // set some default value
887
- if (!width) return null;
888
-
889
- return (
890
- <div
891
- style={
892
- this.props.horizontal
893
- ? { height: width + "px" }
894
- : { width: width + "px" }
895
- }
896
- key={"s" + index}
897
- >
898
- <WellLogSpacer
899
- controllers={
900
- this.controllers
901
- ? [this.controllers[prev], this.controllers[index]]
902
- : []
903
- }
904
- distance={{
905
- units: this.props.wellDistances
906
- ? this.props.wellDistances.units
907
- : "",
908
- value: this.props.wellDistances?.distances[prev],
909
- }}
910
- colorTables={this.props.colorTables}
911
- wellpicks={
912
- this.props.wellpicks
913
- ? [
914
- this.props.wellpicks[prev],
915
- this.props.wellpicks[index],
916
- ]
917
- : []
918
- }
919
- patternsTable={this.props.patternsTable}
920
- patterns={this.props.patterns}
921
- options={this.props.spacerOptions}
922
- horizontal={this.props.horizontal}
923
- onCreateSpacer={(spacer: WellLogSpacer): void => {
924
- this.spacers[index] = spacer;
925
- }}
926
- ></WellLogSpacer>
927
- </div>
928
- );
929
- }
930
-
931
- createRightPanel(): ReactNode {
932
- return (
933
- <div
934
- key="rightPanel"
935
- style={{
936
- flex: "0, 0",
937
- display: "flex",
938
- flexDirection: "column",
939
- height: "100%",
940
- width: "255px",
941
- minWidth: "255px",
942
- maxWidth: "255px",
943
- }}
944
- >
945
- <AxisSelector
946
- header="Primary scale"
947
- axes={this.state.axes}
948
- axisLabels={this.props.axisTitles}
949
- value={this.state.primaryAxis}
950
- onChange={this.onChangePrimaryAxis}
951
- />
952
- {this.props.welllogs.map((_welllog: WellLog, index: number) => (
953
- <InfoPanel
954
- key={index}
955
- header={
956
- "Readout " + this.props.welllogs[index].header.well
957
- }
958
- onGroupClick={this.onInfoGroupClick}
959
- infos={this.state.infos[index]}
960
- />
961
- ))}
962
- <div style={{ paddingLeft: "10px", display: "flex" }}>
963
- <span>Zoom:</span>
964
- <span
965
- style={{
966
- flex: "1 1 100px",
967
- padding: "0 20px 0 10px",
968
- }}
969
- >
970
- <ZoomSlider
971
- value={this.state.sliderValue}
972
- max={
973
- this.props.welllogOptions?.maxContentZoom ||
974
- 256 /*default*/
975
- }
976
- onChange={this.onZoomSliderChange}
977
- />
978
- </span>
979
- </div>
980
- </div>
981
- );
982
- }
983
-
984
- render(): JSX.Element {
985
- return (
986
- <div
987
- style={{
988
- height: "100%",
989
- width: "100%",
990
- display: "flex",
991
- flexDirection: "row",
992
- }}
993
- >
994
- <div
995
- style={{
996
- height: "100%",
997
- width: "255px" /*some small value to be grown by flex*/,
998
- flex: "1 1",
999
- display: "flex",
1000
- flexDirection: this.props.horizontal ? "column" : "row",
1001
- }}
1002
- >
1003
- {this.props.welllogs.map(
1004
- (_welllog: WellLog, index: number) => [
1005
- index ? this.createSpacer(index) : null,
1006
- this.createView(index),
1007
- ]
1008
- )}
1009
- </div>
1010
- {this.createRightPanel()}
1011
- </div>
1012
- );
1013
- }
1014
- }
1015
-
1016
- ///
1017
- const WellLogViewOptions_propTypes = PropTypes.shape({
1018
- /**
1019
- * The maximum zoom value
1020
- */
1021
- maxContentZoom: PropTypes.number,
1022
- /**
1023
- * The maximum number of visible tracks
1024
- */
1025
- maxVisibleTrackNum: PropTypes.number,
1026
- /**
1027
- * Validate JSON datafile against schema
1028
- */
1029
- checkDatafileSchema: PropTypes.bool,
1030
- /**
1031
- * Hide titles of the track. Default is false
1032
- */
1033
- hideTrackTitle: PropTypes.bool,
1034
- /**
1035
- * Hide legends of the track. Default is false
1036
- */
1037
- hideTrackLegend: PropTypes.bool,
1038
- });
1039
-
1040
- const InfoOptions_propTypes = PropTypes.shape({
1041
- /**
1042
- * Show not only visible tracks
1043
- */
1044
- allTracks: PropTypes.bool,
1045
- /**
1046
- * how group values. "" | "track"
1047
- */
1048
- grouping: PropTypes.string,
1049
- });
1050
-
1051
- /*
1052
- */
1053
- SyncLogViewer.propTypes = {
1054
- /**
1055
- * The ID of this component, used to identify dash components
1056
- * in callbacks. The ID needs to be unique across all of the
1057
- * components in an app.
1058
- */
1059
- id: PropTypes.string.isRequired,
1060
-
1061
- /**
1062
- * Array of JSON objects describing well log data
1063
- */
1064
- welllogs: PropTypes.array.isRequired,
1065
-
1066
- /**
1067
- * Prop containing track template data
1068
- */
1069
- templates: PropTypes.array.isRequired,
1070
-
1071
- /**
1072
- * Prop containing color table data
1073
- */
1074
- colorTables: PropTypes.array.isRequired,
1075
-
1076
- /**
1077
- * Well Picks data array
1078
- */
1079
- wellpicks: PropTypes.array,
1080
-
1081
- /**
1082
- * Patterns table
1083
- */
1084
- patternsTable: PropTypes.object,
1085
- /**
1086
- * Horizon to pattern index map
1087
- */
1088
- patterns: PropTypes.array, // [string, number][];
1089
-
1090
- /**
1091
- * Horizon names for wellpick flatting (pan and zoom)
1092
- */
1093
- wellpickFlatting: PropTypes.arrayOf(PropTypes.string),
1094
-
1095
- /**
1096
- * Set to true or to array of spaser widths if WellLogSpacers should be used
1097
- */
1098
- spacers: PropTypes.oneOfType([
1099
- PropTypes.bool,
1100
- PropTypes.arrayOf(PropTypes.number),
1101
- ]),
1102
-
1103
- /**
1104
- * Distanses between wells to show on the spacers
1105
- */
1106
- wellDistances: PropTypes.object,
1107
-
1108
- /**
1109
- * Orientation of the track plots on the screen. Default is false
1110
- */
1111
- horizontal: PropTypes.bool,
1112
-
1113
- /**
1114
- * Primary axis id: " md", "tvd", "time"...
1115
- */
1116
- primaryAxis: PropTypes.string,
1117
-
1118
- /**
1119
- * Log mnemonics for axes
1120
- */
1121
- axisTitles: PropTypes.object,
1122
-
1123
- /**
1124
- * Names for axes
1125
- */
1126
- axisMnemos: PropTypes.object,
1127
-
1128
- /**
1129
- * The maximum zoom value
1130
- */
1131
- maxContentZoom: PropTypes.number,
1132
-
1133
- /**
1134
- * Initial visible interval of the log data
1135
- */
1136
- domain: PropTypes.arrayOf(PropTypes.number),
1137
-
1138
- /**
1139
- * Initial selected interval of the log data
1140
- */
1141
- selection: PropTypes.arrayOf(PropTypes.number),
1142
-
1143
- /**
1144
- * Set to true for default titles or to array of individial welllog titles
1145
- */
1146
- viewTitles: PropTypes.oneOfType([
1147
- PropTypes.bool,
1148
- PropTypes.arrayOf(
1149
- PropTypes.oneOfType([
1150
- PropTypes.bool,
1151
- PropTypes.string,
1152
- PropTypes.object,
1153
- ])
1154
- ) /* bool, string or react element */,
1155
- ]),
1156
-
1157
- /**
1158
- * WellLogView additional options
1159
- */
1160
- welllogOptions: WellLogViewOptions_propTypes /*PropTypes.object,*/,
1161
-
1162
- /**
1163
- * Options for readout panel
1164
- */
1165
- readoutOptions: InfoOptions_propTypes /*PropTypes.object,*/,
1166
-
1167
- /**
1168
- * Synchronize the first visible track number in views
1169
- */
1170
- syncTrackPos: PropTypes.bool,
1171
-
1172
- /**
1173
- * Synchronize the visible area in views
1174
- */
1175
- syncContentDomain: PropTypes.bool,
1176
-
1177
- /**
1178
- * Synchronize the selection (current mouse hover) in views
1179
- */
1180
- syncContentSelection: PropTypes.bool,
1181
-
1182
- /**
1183
- * Synchronize templates in views
1184
- */
1185
- syncTemplate: PropTypes.bool,
1186
- };
1187
-
1188
- export default SyncLogViewer;