@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,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;