1 | import React, { PureComponent } from 'react';
|
2 | import DeckGL from '@deck.gl/react';
|
3 | import { getVivId } from '../views/utils';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | export default class VivViewer extends PureComponent {
|
13 | constructor(props) {
|
14 | super(props);
|
15 | this.state = {
|
16 | viewStates: {},
|
17 | initialViewStates: {}
|
18 | };
|
19 | const { viewStates, initialViewStates } = this.state;
|
20 | const { views } = this.props;
|
21 | views.forEach(view => {
|
22 | viewStates[view.id] = view.filterViewState({
|
23 | viewState: view.initialViewState
|
24 | });
|
25 | initialViewStates[view.id] = view.filterViewState({
|
26 | viewState: view.initialViewState
|
27 | });
|
28 | });
|
29 | this._onViewStateChange = this._onViewStateChange.bind(this);
|
30 | this.layerFilter = this.layerFilter.bind(this);
|
31 | this.onHover = this.onHover.bind(this);
|
32 | }
|
33 |
|
34 | |
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | layerFilter({ layer, viewport }) {
|
44 | return layer.id.includes(getVivId(viewport.id));
|
45 | }
|
46 |
|
47 | |
48 |
|
49 |
|
50 |
|
51 | _onViewStateChange({ viewId, viewState, oldViewState }) {
|
52 |
|
53 | const { views } = this.props;
|
54 | this.setState(prevState => {
|
55 | const viewStates = {};
|
56 | views.forEach(view => {
|
57 | const currentViewState = prevState.viewStates[view.id];
|
58 | viewStates[view.id] = view.filterViewState({
|
59 | viewState: { ...viewState, id: viewId },
|
60 | oldViewState,
|
61 | currentViewState
|
62 | });
|
63 | });
|
64 | return { viewStates };
|
65 | });
|
66 | }
|
67 |
|
68 | |
69 |
|
70 |
|
71 |
|
72 |
|
73 | static getDerivedStateFromProps(props, prevState) {
|
74 | const { views } = props;
|
75 |
|
76 |
|
77 | if (
|
78 | views.some(
|
79 | view =>
|
80 | !prevState.viewStates[view.id] ||
|
81 | view.initialViewState.height !==
|
82 | prevState.viewStates[view.id].height ||
|
83 | view.initialViewState.width !== prevState.viewStates[view.id].width
|
84 | )
|
85 | ) {
|
86 | const viewStates = {};
|
87 | views.forEach(view => {
|
88 | const { height, width } = view.initialViewState;
|
89 | const currentViewState = prevState.viewStates[view.id];
|
90 | viewStates[view.id] = view.filterViewState({
|
91 | viewState: {
|
92 | ...(currentViewState || view.initialViewState),
|
93 | height,
|
94 | width,
|
95 | id: view.id
|
96 | }
|
97 | });
|
98 | });
|
99 | return { viewStates };
|
100 | }
|
101 | if (
|
102 | views.some(
|
103 | view =>
|
104 | view.initialViewState.target !==
|
105 | prevState.initialViewStates[view.id].target ||
|
106 | view.initialViewState.zoom !==
|
107 | prevState.initialViewStates[view.id].zoom
|
108 | )
|
109 | ) {
|
110 | const initialViewStates = {};
|
111 | const viewStates = {};
|
112 | views.forEach(view => {
|
113 | viewStates[view.id] = view.filterViewState({
|
114 | viewState: view.initialViewState
|
115 | });
|
116 | initialViewStates[view.id] = view.filterViewState({
|
117 | viewState: view.initialViewState
|
118 | });
|
119 | });
|
120 | return { initialViewStates, viewStates };
|
121 | }
|
122 | return prevState;
|
123 | }
|
124 |
|
125 |
|
126 | onHover({ sourceLayer, coordinate, layer }) {
|
127 | if (!coordinate) {
|
128 | return null;
|
129 | }
|
130 | const { hoverHooks } = this.props;
|
131 | if (!hoverHooks) {
|
132 | return null;
|
133 | }
|
134 | const { handleValue } = hoverHooks;
|
135 | if (!handleValue) {
|
136 | return null;
|
137 | }
|
138 | const { channelData, bounds } = sourceLayer.props;
|
139 | if (!channelData) {
|
140 | return null;
|
141 | }
|
142 | const { data, width } = channelData;
|
143 | if (!data) {
|
144 | return null;
|
145 | }
|
146 | let dataCoords;
|
147 |
|
148 | if (sourceLayer.id.includes('Tiled')) {
|
149 | const {
|
150 | loader: { tileSize }
|
151 | } = layer.props;
|
152 | const {
|
153 | tileId: { z }
|
154 | } = sourceLayer.props;
|
155 |
|
156 |
|
157 | const layerZoomScale = Math.max(
|
158 | 1,
|
159 | 2 ** Math.round(-z + Math.log2(512 / tileSize))
|
160 | );
|
161 | dataCoords = [
|
162 | Math.floor((coordinate[0] - bounds[0]) / layerZoomScale),
|
163 | Math.floor((coordinate[1] - bounds[3]) / layerZoomScale)
|
164 | ];
|
165 | } else {
|
166 |
|
167 | const { zoom } = layer.context.viewport;
|
168 | const layerZoomScale = Math.max(1, 2 ** Math.floor(-zoom));
|
169 | dataCoords = [
|
170 | Math.floor((coordinate[0] - bounds[0]) / layerZoomScale),
|
171 | Math.floor((coordinate[1] - bounds[3]) / layerZoomScale)
|
172 | ];
|
173 | }
|
174 | const coords = dataCoords[1] * width + dataCoords[0];
|
175 | const hoverData = data.map(d => d[coords]);
|
176 | handleValue(hoverData);
|
177 | }
|
178 |
|
179 | |
180 |
|
181 |
|
182 | _renderLayers() {
|
183 | const { onHover } = this;
|
184 | const { viewStates } = this.state;
|
185 | const { views, layerProps } = this.props;
|
186 | return views.map((view, i) =>
|
187 | view.getLayers({
|
188 | viewStates,
|
189 | props: {
|
190 | ...layerProps[i],
|
191 | onHover
|
192 | }
|
193 | })
|
194 | );
|
195 | }
|
196 |
|
197 | render() {
|
198 |
|
199 | const { views, randomize } = this.props;
|
200 | const { viewStates } = this.state;
|
201 | const deckGLViews = views.map(view => view.getDeckGlView());
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 | if (randomize) {
|
211 | const random = Math.random();
|
212 | const holdFirstElement = deckGLViews[0];
|
213 |
|
214 | const randomWieghted = random * 1.49;
|
215 | const randomizedIndex = Math.round(randomWieghted * (views.length - 1));
|
216 | deckGLViews[0] = deckGLViews[randomizedIndex];
|
217 | deckGLViews[randomizedIndex] = holdFirstElement;
|
218 | }
|
219 | return (
|
220 | <DeckGL
|
221 | glOptions={{ webgl2: true }}
|
222 | layerFilter={this.layerFilter}
|
223 | layers={this._renderLayers()}
|
224 | onViewStateChange={this._onViewStateChange}
|
225 | views={deckGLViews}
|
226 | viewState={viewStates}
|
227 | getCursor={({ isDragging }) => {
|
228 | return isDragging ? 'grabbing' : 'crosshair';
|
229 | }}
|
230 | />
|
231 | );
|
232 |
|
233 |
|
234 | }
|
235 | }
|