@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.
- package/dist/SyncLogViewer.js +3 -4
- package/dist/SyncLogViewer.js.map +1 -1
- package/dist/components/WellLogView.js +5 -5
- package/dist/components/WellLogView.js.map +1 -1
- package/dist/demo/example-data/welllog_template_2.json +167 -167
- package/dist/demo/example-data/wellpick_colors.json +1 -1
- package/dist/demo/example-data/wellpicks.json +179 -179
- package/package.json +32 -5
- package/dist/Intro.stories.mdx +0 -59
- package/dist/package.json +0 -21
- package/src/Intro.stories.mdx +0 -59
- package/src/MapAndWellLogViewer.stories.jsx +0 -147
- package/src/MapAndWellLogViewer.test.tsx +0 -26
- package/src/MapAndWellLogViewer.tsx +0 -473
- package/src/SyncLogViewer.stories.jsx +0 -361
- package/src/SyncLogViewer.test.tsx +0 -41
- package/src/SyncLogViewer.tsx +0 -1188
- package/src/WellLogViewer.png +0 -0
- package/src/WellLogViewer.stories.jsx +0 -169
- package/src/WellLogViewer.test.tsx +0 -53
- package/src/WellLogViewer.tsx +0 -439
- package/src/WellLogViewer_performance.test.tsx +0 -78
- package/src/__snapshots__/MapAndWellLogViewer.test.tsx.snap +0 -365
- package/src/__snapshots__/SyncLogViewer.test.tsx.snap +0 -510
- package/src/__snapshots__/WellLogViewer.test.tsx.snap +0 -552
- package/src/components/AxisSelector.test.tsx +0 -50
- package/src/components/AxisSelector.tsx +0 -49
- package/src/components/ColorTableTypes.ts +0 -9
- package/src/components/InfoPanel.test.tsx +0 -58
- package/src/components/InfoPanel.tsx +0 -144
- package/src/components/InfoTypes.ts +0 -17
- package/src/components/LocalMenus.tsx +0 -336
- package/src/components/PlotDialog.tsx +0 -419
- package/src/components/Scroller.stories.jsx +0 -80
- package/src/components/Scroller.test.tsx +0 -22
- package/src/components/Scroller.tsx +0 -173
- package/src/components/TrackDialog.tsx +0 -217
- package/src/components/WellLogSpacer.tsx +0 -483
- package/src/components/WellLogTemplateTypes.ts +0 -65
- package/src/components/WellLogTypes.ts +0 -53
- package/src/components/WellLogView.stories.jsx +0 -84
- package/src/components/WellLogView.test.tsx +0 -52
- package/src/components/WellLogView.tsx +0 -2063
- package/src/components/WellLogViewWithScroller.stories.jsx +0 -69
- package/src/components/WellLogViewWithScroller.test.tsx +0 -47
- package/src/components/WellLogViewWithScroller.tsx +0 -179
- package/src/components/ZoomSlider.stories.jsx +0 -52
- package/src/components/ZoomSlider.test.tsx +0 -28
- package/src/components/ZoomSlider.tsx +0 -86
- package/src/components/__snapshots__/AxisSelector.test.tsx.snap +0 -28
- package/src/components/__snapshots__/InfoPanel.test.tsx.snap +0 -103
- package/src/components/__snapshots__/Scroller.test.tsx.snap +0 -13
- package/src/components/__snapshots__/WellLogView.test.tsx.snap +0 -54
- package/src/components/__snapshots__/WellLogViewWithScroller.test.tsx.snap +0 -270
- package/src/components/__snapshots__/ZoomSlider.test.tsx.snap +0 -50
- package/src/components/styles.scss +0 -106
- package/src/custom.d.ts +0 -13
- package/src/demo/example-data/volve_logs.json +0 -689617
- package/src/demo/example-data/welllog_template_2.json +0 -196
- package/src/demo/example-data/wellpick_colors.json +0 -156
- package/src/demo/example-data/wellpicks.json +0 -186
- package/src/index.ts +0 -8
- package/src/utils/axes.ts +0 -26
- package/src/utils/color-table.ts +0 -153
- package/src/utils/deepcopy.ts +0 -3
- package/src/utils/edit-track.tsx +0 -40
- package/src/utils/fill-info.ts +0 -224
- package/src/utils/gradientfill-plot-legend.ts +0 -177
- package/src/utils/gradientfill-plot.ts +0 -203
- package/src/utils/graph/factory.ts +0 -15
- package/src/utils/legend/common.ts +0 -153
- package/src/utils/log-viewer.ts +0 -209
- package/src/utils/minmax.ts +0 -126
- package/src/utils/pattern.tsx +0 -50
- package/src/utils/stack/stack-legend.ts +0 -100
- package/src/utils/tracks.ts +0 -1559
- package/tsconfig.json +0 -8
|
@@ -1,419 +0,0 @@
|
|
|
1
|
-
import React, { Component, ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
import { Track, GraphTrack } from "@equinor/videx-wellog";
|
|
4
|
-
|
|
5
|
-
import { TemplatePlot, TemplatePlotTypes } from "./WellLogTemplateTypes";
|
|
6
|
-
import { WellLog } from "./WellLogTypes";
|
|
7
|
-
import { ColorTable } from "./ColorTableTypes";
|
|
8
|
-
|
|
9
|
-
import WellLogView from "./WellLogView";
|
|
10
|
-
|
|
11
|
-
// material ui
|
|
12
|
-
import {
|
|
13
|
-
Dialog,
|
|
14
|
-
DialogTitle,
|
|
15
|
-
DialogContent,
|
|
16
|
-
DialogActions,
|
|
17
|
-
Button,
|
|
18
|
-
FormControl,
|
|
19
|
-
InputLabel,
|
|
20
|
-
NativeSelect,
|
|
21
|
-
} from "@mui/material";
|
|
22
|
-
import { getTrackTemplate } from "../utils/tracks";
|
|
23
|
-
|
|
24
|
-
const typeItems: Record<string, string> = {
|
|
25
|
-
// language dependent names of plot types
|
|
26
|
-
line: "Line",
|
|
27
|
-
linestep: "Line Step",
|
|
28
|
-
dot: "Dot",
|
|
29
|
-
area: "Area",
|
|
30
|
-
gradientfill: "Gradient Fill",
|
|
31
|
-
differential: "Differential",
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const scaleItems: Record<string, string> = {
|
|
35
|
-
// language dependent names of plot types
|
|
36
|
-
linear: "Linear",
|
|
37
|
-
log: "Logarithmic",
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const colorItems: Record<string, string> = {
|
|
41
|
-
// language dependent names of colors
|
|
42
|
-
black: "Black",
|
|
43
|
-
red: "Red",
|
|
44
|
-
green: "Green",
|
|
45
|
-
blue: "Blue",
|
|
46
|
-
brown: "Brown",
|
|
47
|
-
magenta: "Magenta",
|
|
48
|
-
orange: "Orange",
|
|
49
|
-
gray: "Gray",
|
|
50
|
-
darkred: "Dark red",
|
|
51
|
-
lightgreen: "Light green",
|
|
52
|
-
lightblue: "Light blue",
|
|
53
|
-
yellow: "Yellow",
|
|
54
|
-
white: "White",
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const noneValue = "-";
|
|
58
|
-
|
|
59
|
-
export function _createItems(items: Record<string, string>): ReactNode[] {
|
|
60
|
-
const nodes: ReactNode[] = [];
|
|
61
|
-
for (const key in items) {
|
|
62
|
-
nodes.push(
|
|
63
|
-
<option key={key} value={key}>
|
|
64
|
-
{items[key]}
|
|
65
|
-
</option>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
return nodes;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function createTypeItems(): ReactNode[] {
|
|
72
|
-
return _createItems(typeItems);
|
|
73
|
-
}
|
|
74
|
-
export function createScaleItems(): ReactNode[] {
|
|
75
|
-
return _createItems(scaleItems);
|
|
76
|
-
}
|
|
77
|
-
function createColorItems(): ReactNode[] {
|
|
78
|
-
return _createItems(colorItems);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function createColorTableItems(colorTables: ColorTable[]): ReactNode[] {
|
|
82
|
-
const nodes: ReactNode[] = [];
|
|
83
|
-
for (const colorTable of colorTables) {
|
|
84
|
-
if (colorTable.discrete)
|
|
85
|
-
// skip discrete color tables
|
|
86
|
-
continue;
|
|
87
|
-
nodes.push(<option key={colorTable.name}>{colorTable.name}</option>);
|
|
88
|
-
}
|
|
89
|
-
return nodes;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function createDataItem(item: string): ReactNode {
|
|
93
|
-
return (
|
|
94
|
-
<option key={item} value={item}>
|
|
95
|
-
{item}
|
|
96
|
-
</option>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function dataNames(
|
|
101
|
-
welllog: WellLog | undefined,
|
|
102
|
-
track: Track | null,
|
|
103
|
-
discrete?: boolean
|
|
104
|
-
): string[] {
|
|
105
|
-
const names: string[] = [];
|
|
106
|
-
if (welllog) {
|
|
107
|
-
const skipUsed = !!track;
|
|
108
|
-
const plots = track ? (track as GraphTrack).plots : undefined;
|
|
109
|
-
const abbr = track ? track.options.abbr : undefined;
|
|
110
|
-
|
|
111
|
-
const curves = welllog.curves;
|
|
112
|
-
let iCurve = 0;
|
|
113
|
-
for (const curve of curves) {
|
|
114
|
-
if (
|
|
115
|
-
discrete &&
|
|
116
|
-
curve.valueType !== "string" &&
|
|
117
|
-
curve.valueType !== "integer"
|
|
118
|
-
)
|
|
119
|
-
continue;
|
|
120
|
-
|
|
121
|
-
let bUsed = false;
|
|
122
|
-
if (plots) {
|
|
123
|
-
// GraphTrack
|
|
124
|
-
for (const plot of plots)
|
|
125
|
-
if (plot.id == iCurve) {
|
|
126
|
-
bUsed = true;
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
} else if (abbr === curve.name) {
|
|
130
|
-
// Scale tracks?
|
|
131
|
-
bUsed = true;
|
|
132
|
-
}
|
|
133
|
-
if (!bUsed || !skipUsed) names.push(curve.name);
|
|
134
|
-
iCurve++;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return names;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function createDataItems(
|
|
141
|
-
welllog: WellLog | undefined,
|
|
142
|
-
track: Track | null,
|
|
143
|
-
discrete?: boolean
|
|
144
|
-
): ReactNode[] {
|
|
145
|
-
const names = dataNames(welllog, track, discrete);
|
|
146
|
-
return names.map((name) => createDataItem(name));
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
interface Props {
|
|
150
|
-
templatePlot?: TemplatePlot; // input for editting
|
|
151
|
-
onOK: (templatePlot: TemplatePlot) => void;
|
|
152
|
-
wellLogView: WellLogView;
|
|
153
|
-
track: Track;
|
|
154
|
-
}
|
|
155
|
-
interface State extends TemplatePlot {
|
|
156
|
-
open: boolean;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export class PlotPropertiesDialog extends Component<Props, State> {
|
|
160
|
-
constructor(props: Props) {
|
|
161
|
-
super(props);
|
|
162
|
-
let name = "",
|
|
163
|
-
name2 = "";
|
|
164
|
-
const names = this.dataNames(true);
|
|
165
|
-
if (names[0]) name2 = name = names[0];
|
|
166
|
-
if (names[1]) name2 = names[1];
|
|
167
|
-
|
|
168
|
-
const trackTemplate = getTrackTemplate(this.props.track);
|
|
169
|
-
const templatePlot = this.props.templatePlot;
|
|
170
|
-
this.state = templatePlot
|
|
171
|
-
? {
|
|
172
|
-
...templatePlot,
|
|
173
|
-
|
|
174
|
-
open: true,
|
|
175
|
-
}
|
|
176
|
-
: {
|
|
177
|
-
// we should fill every posible state to allow this.setState() to set it
|
|
178
|
-
type: trackTemplate.scale ? "" : "line",
|
|
179
|
-
name: name, //?? the first data in data selector
|
|
180
|
-
name2: name2, //? the second data in data selector ??
|
|
181
|
-
|
|
182
|
-
scale: undefined,
|
|
183
|
-
color: "black", //??
|
|
184
|
-
|
|
185
|
-
// for 'area' plot
|
|
186
|
-
fill: "red",
|
|
187
|
-
fillOpacity: 0.25,
|
|
188
|
-
inverseColor: "",
|
|
189
|
-
|
|
190
|
-
// for 'gradientfill' plot
|
|
191
|
-
colorTable: this.props.wellLogView.props.colorTables[0].name,
|
|
192
|
-
inverseColorTable: undefined,
|
|
193
|
-
colorScale: undefined,
|
|
194
|
-
inverseColorScale: undefined,
|
|
195
|
-
|
|
196
|
-
// for 'differential' plot
|
|
197
|
-
color2: "black", //??
|
|
198
|
-
fill2: "green",
|
|
199
|
-
|
|
200
|
-
open: true,
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
this.closeDialog = this.closeDialog.bind(this);
|
|
204
|
-
this.onOK = this.onOK.bind(this);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
componentDidUpdate(_prevProps: Props, prevState: State): void {
|
|
208
|
-
if (this.state.type !== prevState.type) {
|
|
209
|
-
if (this.state.type === "area") {
|
|
210
|
-
if (!this.state.fill) this.setState({ fill: "black" });
|
|
211
|
-
} else if (this.state.type === "gradientfill") {
|
|
212
|
-
if (this.state.inverseColor)
|
|
213
|
-
this.setState({ inverseColor: "" });
|
|
214
|
-
} else if (this.state.type === "differential") {
|
|
215
|
-
if (!this.state.name2) {
|
|
216
|
-
const skipUsed = this.props.templatePlot
|
|
217
|
-
? false
|
|
218
|
-
: true; /*??*/
|
|
219
|
-
this.setState({ name2: this.dataNames(skipUsed)[0] });
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
onOK(): void {
|
|
226
|
-
this.props.onOK(this.state);
|
|
227
|
-
this.closeDialog();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
closeDialog(): void {
|
|
231
|
-
this.setState({ open: false });
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
dataNames(skipUsed: boolean): string[] {
|
|
235
|
-
return dataNames(
|
|
236
|
-
this.props.wellLogView.props.welllog,
|
|
237
|
-
skipUsed ? this.props.track : null
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
createDataItems(skipUsed: boolean): ReactNode[] {
|
|
242
|
-
const names = this.dataNames(skipUsed);
|
|
243
|
-
return names.map((name) => createDataItem(name));
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
createSelectControl(
|
|
247
|
-
valueName: string, // use it as "a pointer to member" of an object
|
|
248
|
-
label: string,
|
|
249
|
-
nodes: ReactNode[],
|
|
250
|
-
insertEmpty?: string | boolean
|
|
251
|
-
): ReactNode {
|
|
252
|
-
let value = (this.state as unknown as Record<string, string>)[
|
|
253
|
-
valueName
|
|
254
|
-
];
|
|
255
|
-
if (insertEmpty) {
|
|
256
|
-
if (!value) value = noneValue;
|
|
257
|
-
// insert at the beginning
|
|
258
|
-
nodes.unshift(
|
|
259
|
-
<option key={noneValue} value={noneValue}>
|
|
260
|
-
{insertEmpty == true ? "\u2014" : insertEmpty}
|
|
261
|
-
</option>
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
return (
|
|
265
|
-
<FormControl fullWidth>
|
|
266
|
-
<InputLabel>{label}</InputLabel>
|
|
267
|
-
<NativeSelect
|
|
268
|
-
value={value}
|
|
269
|
-
onChange={(event) => {
|
|
270
|
-
const value =
|
|
271
|
-
event.currentTarget.value === noneValue
|
|
272
|
-
? ""
|
|
273
|
-
: event.currentTarget.value;
|
|
274
|
-
|
|
275
|
-
const values = new Object() as Record<string, string>;
|
|
276
|
-
values[valueName] = value;
|
|
277
|
-
this.setState(values as unknown as State);
|
|
278
|
-
}}
|
|
279
|
-
>
|
|
280
|
-
{nodes}
|
|
281
|
-
</NativeSelect>
|
|
282
|
-
</FormControl>
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
createSelectControlFromType(type: TemplatePlotTypes): ReactNode {
|
|
287
|
-
if (type === "area" || type === "differential") {
|
|
288
|
-
return [
|
|
289
|
-
this.createSelectControl(
|
|
290
|
-
"fill",
|
|
291
|
-
"Fill Color",
|
|
292
|
-
createColorItems()
|
|
293
|
-
),
|
|
294
|
-
<FormControl fullWidth key="112" />,
|
|
295
|
-
<FormControl fullWidth key="113" />,
|
|
296
|
-
this.state.type === "area" ? (
|
|
297
|
-
this.createSelectControl(
|
|
298
|
-
"inverseColor",
|
|
299
|
-
"Inverse Color",
|
|
300
|
-
createColorItems(),
|
|
301
|
-
true
|
|
302
|
-
)
|
|
303
|
-
) : (
|
|
304
|
-
<FormControl fullWidth />
|
|
305
|
-
),
|
|
306
|
-
];
|
|
307
|
-
} else if (type === "gradientfill") {
|
|
308
|
-
const colorTables = this.props.wellLogView.props.colorTables;
|
|
309
|
-
[
|
|
310
|
-
this.createSelectControl(
|
|
311
|
-
"colorTable",
|
|
312
|
-
"Fill Color table",
|
|
313
|
-
createColorTableItems(colorTables)
|
|
314
|
-
),
|
|
315
|
-
<FormControl fullWidth key="211" />,
|
|
316
|
-
<FormControl fullWidth key="212" />,
|
|
317
|
-
this.createSelectControl(
|
|
318
|
-
"inverseColorTable",
|
|
319
|
-
"Inverse Color table",
|
|
320
|
-
createColorTableItems(colorTables),
|
|
321
|
-
true
|
|
322
|
-
),
|
|
323
|
-
];
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return [];
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
render(): JSX.Element {
|
|
330
|
-
const trackTemplate = getTrackTemplate(this.props.track);
|
|
331
|
-
const title = this.props.templatePlot ? "Edit plot" : "Add New Plot";
|
|
332
|
-
const skipUsed = this.props.templatePlot ? false : true; /*??*/
|
|
333
|
-
const scale = this.state.scale || trackTemplate.scale;
|
|
334
|
-
return (
|
|
335
|
-
<Dialog
|
|
336
|
-
open={this.state.open}
|
|
337
|
-
maxWidth="sm"
|
|
338
|
-
fullWidth
|
|
339
|
-
onClose={() => this.setState({ open: false })}
|
|
340
|
-
>
|
|
341
|
-
<DialogTitle>{title}</DialogTitle>
|
|
342
|
-
<DialogContent
|
|
343
|
-
style={{
|
|
344
|
-
display: "grid",
|
|
345
|
-
gridTemplateColumns: "1fr 1fr 1fr",
|
|
346
|
-
}}
|
|
347
|
-
>
|
|
348
|
-
{this.createSelectControl(
|
|
349
|
-
"type",
|
|
350
|
-
"Type",
|
|
351
|
-
createTypeItems()
|
|
352
|
-
)}
|
|
353
|
-
{this.createSelectControl(
|
|
354
|
-
"scale",
|
|
355
|
-
"Scale",
|
|
356
|
-
createScaleItems(),
|
|
357
|
-
"Track scale"
|
|
358
|
-
)}
|
|
359
|
-
{this.state.type === "gradientfill" && scale === "linear"
|
|
360
|
-
? [
|
|
361
|
-
this.createSelectControl(
|
|
362
|
-
"colorScale",
|
|
363
|
-
"Color Scale",
|
|
364
|
-
createScaleItems()
|
|
365
|
-
),
|
|
366
|
-
]
|
|
367
|
-
: [<FormControl fullWidth key="12" />]}
|
|
368
|
-
|
|
369
|
-
{this.createSelectControl(
|
|
370
|
-
"name",
|
|
371
|
-
"Data",
|
|
372
|
-
this.createDataItems(skipUsed)
|
|
373
|
-
)}
|
|
374
|
-
{this.createSelectControl(
|
|
375
|
-
"color",
|
|
376
|
-
this.state.type === "dot" ? "Dot Color" : "Line Color",
|
|
377
|
-
createColorItems()
|
|
378
|
-
)}
|
|
379
|
-
{this.createSelectControlFromType(this.state.type)}
|
|
380
|
-
{this.state.type === "differential"
|
|
381
|
-
? [
|
|
382
|
-
this.createSelectControl(
|
|
383
|
-
"name2",
|
|
384
|
-
"Data 2",
|
|
385
|
-
this.createDataItems(skipUsed)
|
|
386
|
-
),
|
|
387
|
-
this.createSelectControl(
|
|
388
|
-
"color2",
|
|
389
|
-
"Line Color 2",
|
|
390
|
-
createColorItems()
|
|
391
|
-
),
|
|
392
|
-
this.createSelectControl(
|
|
393
|
-
"fill2",
|
|
394
|
-
"Fill Color 2",
|
|
395
|
-
createColorItems()
|
|
396
|
-
),
|
|
397
|
-
]
|
|
398
|
-
: []}
|
|
399
|
-
</DialogContent>
|
|
400
|
-
<DialogActions>
|
|
401
|
-
<Button
|
|
402
|
-
color="secondary"
|
|
403
|
-
variant="contained"
|
|
404
|
-
onClick={this.closeDialog}
|
|
405
|
-
>
|
|
406
|
-
Cancel
|
|
407
|
-
</Button>
|
|
408
|
-
<Button
|
|
409
|
-
color="primary"
|
|
410
|
-
variant="contained"
|
|
411
|
-
onClick={this.onOK}
|
|
412
|
-
>
|
|
413
|
-
OK
|
|
414
|
-
</Button>
|
|
415
|
-
</DialogActions>
|
|
416
|
-
</Dialog>
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import Scroller from "./Scroller";
|
|
3
|
-
|
|
4
|
-
const ComponentCode =
|
|
5
|
-
"const infoRef = React.useRef(); \r\n" +
|
|
6
|
-
"const setInfo = function (info) { \r\n" +
|
|
7
|
-
" if (infoRef.current) infoRef.current.innerHTML = info; \r\n" +
|
|
8
|
-
"}; \r\n" +
|
|
9
|
-
"return ( \r\n" +
|
|
10
|
-
' <div style={{ height: "92vh" }}> \r\n' +
|
|
11
|
-
" <Scroller \r\n" +
|
|
12
|
-
" ref={(el) => { \r\n" +
|
|
13
|
-
" el.zoom(10, 10); \r\n" +
|
|
14
|
-
" el.scrollTo(0.2, 0.2); \r\n" +
|
|
15
|
-
" }} \r\n" +
|
|
16
|
-
" onScroll={(x, y) => { \r\n" +
|
|
17
|
-
" setInfo( \r\n" +
|
|
18
|
-
' "Scroll position X=" + \r\n' +
|
|
19
|
-
" x.toFixed(2) + \r\n" +
|
|
20
|
-
' ", Y=" + \r\n' +
|
|
21
|
-
" y.toFixed(2) \r\n" +
|
|
22
|
-
" ); \r\n" +
|
|
23
|
-
" }} \r\n" +
|
|
24
|
-
" > \r\n" +
|
|
25
|
-
" <div ref={infoRef}></div> \r\n" +
|
|
26
|
-
" </Scroller> \r\n" +
|
|
27
|
-
" </div> \r\n" +
|
|
28
|
-
"); \r\n";
|
|
29
|
-
|
|
30
|
-
export default {
|
|
31
|
-
component: Scroller,
|
|
32
|
-
title: "WellLogViewer/Components/Scroller",
|
|
33
|
-
parameters: {
|
|
34
|
-
docs: {
|
|
35
|
-
description: {
|
|
36
|
-
component: "Auxiliary component to create scrolbars.",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
componentSource: {
|
|
40
|
-
code: ComponentCode,
|
|
41
|
-
language: "javascript",
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
argTypes: {
|
|
45
|
-
onScroll: {
|
|
46
|
-
description: "Callback with new scroll positions",
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const Template = (args) => {
|
|
52
|
-
const infoRef = React.useRef();
|
|
53
|
-
const setInfo = function (info) {
|
|
54
|
-
if (infoRef.current) infoRef.current.innerHTML = info;
|
|
55
|
-
};
|
|
56
|
-
return (
|
|
57
|
-
<div style={{ height: "92vh" }}>
|
|
58
|
-
<Scroller
|
|
59
|
-
ref={(el) => {
|
|
60
|
-
el.zoom(10, 10);
|
|
61
|
-
el.scrollTo(0.2, 0.2);
|
|
62
|
-
}}
|
|
63
|
-
onScroll={(x, y) => {
|
|
64
|
-
setInfo(
|
|
65
|
-
"Scroll position X=" +
|
|
66
|
-
x.toFixed(2) +
|
|
67
|
-
", Y=" +
|
|
68
|
-
y.toFixed(2)
|
|
69
|
-
);
|
|
70
|
-
args.onScroll(x, y); // for storybook addon Actions Tab
|
|
71
|
-
}}
|
|
72
|
-
>
|
|
73
|
-
<div ref={infoRef}></div>
|
|
74
|
-
</Scroller>
|
|
75
|
-
</div>
|
|
76
|
-
);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
export const Default = Template.bind({});
|
|
80
|
-
Default.args = {};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { render } from "@testing-library/react";
|
|
2
|
-
import "jest-styled-components";
|
|
3
|
-
import "@testing-library/jest-dom";
|
|
4
|
-
import React from "react";
|
|
5
|
-
import Scroller from "./Scroller";
|
|
6
|
-
|
|
7
|
-
window.ResizeObserver =
|
|
8
|
-
window.ResizeObserver ||
|
|
9
|
-
jest.fn().mockImplementation(() => ({
|
|
10
|
-
disconnect: jest.fn(),
|
|
11
|
-
observe: jest.fn(),
|
|
12
|
-
unobserve: jest.fn(),
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
describe("Test scroller", () => {
|
|
16
|
-
it("snapshot test", () => {
|
|
17
|
-
const { container } = render(
|
|
18
|
-
<Scroller onScroll={(x: number, y: number) => [x, y]} />
|
|
19
|
-
);
|
|
20
|
-
expect(container.firstChild).toMatchSnapshot();
|
|
21
|
-
});
|
|
22
|
-
});
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import React, { Component, ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
function getScrollbarSizes(): { vertical: number; horizontal: number } {
|
|
4
|
-
// Creating invisible container
|
|
5
|
-
const outer = document.createElement("div");
|
|
6
|
-
outer.style.visibility = "hidden";
|
|
7
|
-
outer.style.overflow = "scroll"; // forcing scrollbar to appear
|
|
8
|
-
//!!! commented to avoid error TS2339: Property 'msOverflowStyle' does not exist on type 'CSSStyleDeclaration'.
|
|
9
|
-
//!!! outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
|
|
10
|
-
document.body.appendChild(outer);
|
|
11
|
-
|
|
12
|
-
const vertical = outer.offsetWidth - outer.clientWidth;
|
|
13
|
-
const horizontal = outer.offsetHeight - outer.clientHeight;
|
|
14
|
-
|
|
15
|
-
// Removing temporary elements from the DOM
|
|
16
|
-
document.body.removeChild(outer);
|
|
17
|
-
|
|
18
|
-
return { vertical, horizontal };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface Props {
|
|
22
|
-
/**
|
|
23
|
-
* callback with new scroll positions
|
|
24
|
-
*/
|
|
25
|
-
onScroll?: (x: number, y: number) => void;
|
|
26
|
-
children?: ReactNode;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
class Scroller extends Component<Props> {
|
|
30
|
-
scroller: HTMLDivElement | null; // Outer
|
|
31
|
-
scrollable: HTMLDivElement | null; // Inner
|
|
32
|
-
content: HTMLDivElement | null; // Content over inner
|
|
33
|
-
resizeObserver: ResizeObserver;
|
|
34
|
-
|
|
35
|
-
constructor(props: Props) {
|
|
36
|
-
super(props);
|
|
37
|
-
this.scroller = null;
|
|
38
|
-
this.scrollable = null;
|
|
39
|
-
this.content = null;
|
|
40
|
-
|
|
41
|
-
this.resizeObserver = new ResizeObserver((entries) => {
|
|
42
|
-
const entry = entries[0];
|
|
43
|
-
if (entry && entry.target) {
|
|
44
|
-
const Width = (entry.target as HTMLElement).offsetWidth;
|
|
45
|
-
const Height = (entry.target as HTMLElement).offsetHeight;
|
|
46
|
-
|
|
47
|
-
if (this.content) {
|
|
48
|
-
const { vertical, horizontal } = getScrollbarSizes();
|
|
49
|
-
|
|
50
|
-
this.content.style.width = Width - vertical + "px";
|
|
51
|
-
this.content.style.height = Height - horizontal + "px";
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
this.onScroll = this.onScroll.bind(this);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
componentDidMount(): void {
|
|
60
|
-
if (this.scroller) this.resizeObserver.observe(this.scroller);
|
|
61
|
-
}
|
|
62
|
-
componentWillUnmount(): void {
|
|
63
|
-
if (this.scroller) this.resizeObserver.unobserve(this.scroller);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/* current position access functions */
|
|
67
|
-
getScrollX(): number {
|
|
68
|
-
const elOuter = this.scroller;
|
|
69
|
-
if (!elOuter) return 0;
|
|
70
|
-
const scrollWidth = elOuter.scrollWidth - elOuter.clientWidth;
|
|
71
|
-
return scrollWidth ? elOuter.scrollLeft / scrollWidth : 0;
|
|
72
|
-
}
|
|
73
|
-
getScrollY(): number {
|
|
74
|
-
const elOuter = this.scroller;
|
|
75
|
-
if (!elOuter) return 0;
|
|
76
|
-
const scrollHeight = elOuter.scrollHeight - elOuter.clientHeight;
|
|
77
|
-
return scrollHeight ? elOuter.scrollTop / scrollHeight : 0;
|
|
78
|
-
}
|
|
79
|
-
getScrollPos(vertical: boolean | undefined): number {
|
|
80
|
-
return vertical ? this.getScrollY() : this.getScrollX();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* callback from HTML element
|
|
85
|
-
*/
|
|
86
|
-
onScroll(): void {
|
|
87
|
-
const elOuter = this.scroller;
|
|
88
|
-
if (!elOuter) return;
|
|
89
|
-
// notify parent
|
|
90
|
-
if (this.props.onScroll)
|
|
91
|
-
this.props.onScroll(this.getScrollX(), this.getScrollY());
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/* functions to externally set zoom and scroll position */
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* @param x value to set the horizontal beginning of visible part of content (fraction)
|
|
98
|
-
* @param y value to set the vertical beginning of visible part of content (fraction)
|
|
99
|
-
* @returns true if visible part is changed
|
|
100
|
-
*/
|
|
101
|
-
scrollTo(x: number, y: number): boolean {
|
|
102
|
-
if (x < 0.0) x = 0.0;
|
|
103
|
-
else if (x > 1.0) x = 1.0;
|
|
104
|
-
if (y < 0.0) y = 0.0;
|
|
105
|
-
else if (y > 1.0) y = 1.0;
|
|
106
|
-
|
|
107
|
-
const elOuter = this.scroller;
|
|
108
|
-
if (!elOuter) return false;
|
|
109
|
-
|
|
110
|
-
const scrollLeft = Math.round(
|
|
111
|
-
x * (elOuter.scrollWidth - elOuter.clientWidth)
|
|
112
|
-
);
|
|
113
|
-
const scrollTop = Math.round(
|
|
114
|
-
y * (elOuter.scrollHeight - elOuter.clientHeight)
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
elOuter.scrollLeft !== scrollLeft ||
|
|
119
|
-
elOuter.scrollTop !== scrollTop
|
|
120
|
-
) {
|
|
121
|
-
elOuter.scrollTo(scrollLeft, scrollTop);
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* @param xZoom set X zoom factor of visible part of content
|
|
128
|
-
* @param yZoom set Y zoom factor of visible part of content
|
|
129
|
-
* @returns true if visible part is changed
|
|
130
|
-
*/
|
|
131
|
-
zoom(xZoom: number, yZoom: number): boolean {
|
|
132
|
-
const elOuter = this.scroller;
|
|
133
|
-
if (!elOuter) return false;
|
|
134
|
-
|
|
135
|
-
const elInner = this.scrollable;
|
|
136
|
-
if (!elInner) return false;
|
|
137
|
-
|
|
138
|
-
const widthInner = Math.round(elOuter.clientWidth * xZoom) + "px";
|
|
139
|
-
const heightInner = Math.round(elOuter.clientHeight * yZoom) + "px";
|
|
140
|
-
|
|
141
|
-
if (
|
|
142
|
-
elInner.style.width !== widthInner ||
|
|
143
|
-
elInner.style.height !== heightInner
|
|
144
|
-
) {
|
|
145
|
-
elInner.style.width = widthInner;
|
|
146
|
-
elInner.style.height = heightInner;
|
|
147
|
-
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
render(): JSX.Element {
|
|
154
|
-
return (
|
|
155
|
-
<div
|
|
156
|
-
ref={(el) => (this.scroller = el as HTMLDivElement)}
|
|
157
|
-
style={{ overflow: "scroll", width: "100%", height: "100%" }}
|
|
158
|
-
onScroll={this.onScroll}
|
|
159
|
-
>
|
|
160
|
-
<div ref={(el) => (this.scrollable = el as HTMLDivElement)}>
|
|
161
|
-
<div
|
|
162
|
-
ref={(el) => (this.content = el as HTMLDivElement)}
|
|
163
|
-
style={{ position: "absolute" }}
|
|
164
|
-
>
|
|
165
|
-
{this.props.children}
|
|
166
|
-
</div>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export default Scroller;
|