@windborne/grapher 1.0.26 → 1.0.27
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/bundle.cjs +1 -1
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.esm.js +1 -1
- package/dist/bundle.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/range_graph.jsx +2 -0
- package/src/grapher.scss +2 -1
- package/src/renderer/graph_body_renderer.js +72 -38
- package/src/renderer/line_program.js +3 -3
- package/src/renderer/shadow_program.js +74 -51
package/package.json
CHANGED
|
@@ -335,6 +335,8 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
335
335
|
width={pixelMaxX - pixelMinX}
|
|
336
336
|
height={totalHeight}
|
|
337
337
|
className="target-selection-outline"
|
|
338
|
+
onMouseDown={this.startScroll}
|
|
339
|
+
onTouchStart={this.startScroll}
|
|
338
340
|
/>
|
|
339
341
|
</g>
|
|
340
342
|
|
package/src/grapher.scss
CHANGED
|
@@ -109,7 +109,23 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
let cutoffIndex = -1;
|
|
112
|
-
|
|
112
|
+
let cutoffTime = null;
|
|
113
|
+
let cutoffData = singleSeries.data;
|
|
114
|
+
|
|
115
|
+
const isObjectFormat = singleSeries.data && singleSeries.data.length > 0 &&
|
|
116
|
+
typeof singleSeries.data[0] === 'object' &&
|
|
117
|
+
!Array.isArray(singleSeries.data[0]);
|
|
118
|
+
|
|
119
|
+
if (isObjectFormat && singleSeries.cutoffTime) {
|
|
120
|
+
cutoffData = singleSeries.data.map(point => {
|
|
121
|
+
const xValue = point[singleSeries.xKey || 'x'];
|
|
122
|
+
const yValue = point[singleSeries.yKey || 'y'];
|
|
123
|
+
|
|
124
|
+
const convertedX = typeof xValue === 'string' ? new Date(xValue) : xValue;
|
|
125
|
+
|
|
126
|
+
return [convertedX, yValue];
|
|
127
|
+
});
|
|
128
|
+
}
|
|
113
129
|
|
|
114
130
|
if (singleSeries.cutoffTime && singleSeries.data && singleSeries.data.length > 0) {
|
|
115
131
|
let cutoffDate;
|
|
@@ -121,40 +137,48 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
121
137
|
cutoffDate = singleSeries.cutoffTime;
|
|
122
138
|
}
|
|
123
139
|
|
|
124
|
-
|
|
125
|
-
const cutoffTime = cutoffDate instanceof Date ? cutoffDate.getTime() : cutoffDate;
|
|
140
|
+
cutoffTime = cutoffDate instanceof Date ? cutoffDate.getTime() : cutoffDate;
|
|
126
141
|
|
|
127
|
-
for (let i = 0; i <
|
|
128
|
-
const currentPoint =
|
|
129
|
-
const nextPoint =
|
|
142
|
+
for (let i = 0; i < cutoffData.length - 1; i++) {
|
|
143
|
+
const currentPoint = cutoffData[i];
|
|
144
|
+
const nextPoint = cutoffData[i + 1];
|
|
130
145
|
|
|
131
|
-
const currentTime =
|
|
132
|
-
|
|
133
|
-
const nextTime = Array.isArray(nextPoint) ?
|
|
134
|
-
(nextPoint[0] instanceof Date ? nextPoint[0].getTime() : nextPoint[0]) : (i + 1);
|
|
146
|
+
const currentTime = currentPoint[0] instanceof Date ? currentPoint[0].getTime() : currentPoint[0];
|
|
147
|
+
const nextTime = nextPoint[0] instanceof Date ? nextPoint[0].getTime() : nextPoint[0];
|
|
135
148
|
|
|
136
149
|
if (currentTime <= cutoffTime && cutoffTime <= nextTime) {
|
|
137
|
-
// interpolate exact position between these two points
|
|
138
150
|
const timeRatio = (cutoffTime - currentTime) / (nextTime - currentTime);
|
|
139
151
|
cutoffIndex = i + timeRatio;
|
|
140
152
|
break;
|
|
141
153
|
} else if (currentTime > cutoffTime) {
|
|
142
|
-
// cutoff is before the first data point
|
|
143
154
|
cutoffIndex = i;
|
|
144
155
|
break;
|
|
145
156
|
}
|
|
146
157
|
}
|
|
147
158
|
|
|
148
|
-
// cutoff is after all data points
|
|
149
159
|
if (cutoffIndex === -1) {
|
|
150
|
-
cutoffIndex =
|
|
160
|
+
cutoffIndex = cutoffData.length - 1;
|
|
151
161
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// Note: cutoffIndex is used for cutoff calculations but we no longer split data
|
|
155
162
|
}
|
|
156
163
|
|
|
157
164
|
const getIndividualPoints = (useDataSpace) => {
|
|
165
|
+
if (!useDataSpace && inRenderSpace && inRenderSpace.yValues) {
|
|
166
|
+
const individualPoints = [];
|
|
167
|
+
const { yValues, nullMask } = inRenderSpace;
|
|
168
|
+
|
|
169
|
+
for (let pixelX = 0; pixelX < yValues.length; pixelX++) {
|
|
170
|
+
if (nullMask[pixelX] === 0) {
|
|
171
|
+
individualPoints.push([pixelX, yValues[pixelX]]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (individualPoints.length === 0) {
|
|
176
|
+
return getIndividualPoints(true);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return individualPoints;
|
|
180
|
+
}
|
|
181
|
+
|
|
158
182
|
if (!bounds) {
|
|
159
183
|
bounds = singleSeries.axis.currentBounds;
|
|
160
184
|
}
|
|
@@ -165,17 +189,33 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
165
189
|
data = singleSeries.inDataSpace;
|
|
166
190
|
}
|
|
167
191
|
|
|
168
|
-
for (let
|
|
169
|
-
|
|
192
|
+
for (let i = 0; i < data.length; i++) {
|
|
193
|
+
let x, y;
|
|
194
|
+
|
|
195
|
+
if (Array.isArray(data[i])) {
|
|
196
|
+
[x, y] = data[i];
|
|
197
|
+
} else if (typeof data[i] === 'object' && data[i] !== null) {
|
|
198
|
+
x = data[i][singleSeries.xKey];
|
|
199
|
+
y = data[i][singleSeries.yKey];
|
|
200
|
+
} else {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (y === null || y === undefined) {
|
|
170
205
|
continue;
|
|
171
206
|
}
|
|
172
207
|
|
|
208
|
+
let xValue = x instanceof Date ? x.getTime() : x;
|
|
209
|
+
let boundsMinX = bounds.minX instanceof Date ? bounds.minX.getTime() : bounds.minX;
|
|
210
|
+
let boundsMaxX = bounds.maxX instanceof Date ? bounds.maxX.getTime() : bounds.maxX;
|
|
211
|
+
|
|
173
212
|
individualPoints.push([
|
|
174
|
-
(
|
|
213
|
+
(xValue - boundsMinX) / (boundsMaxX - boundsMinX) * this._sizing.renderWidth,
|
|
175
214
|
(1.0 - (y - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight
|
|
176
215
|
]);
|
|
177
216
|
}
|
|
178
217
|
|
|
218
|
+
|
|
179
219
|
return individualPoints;
|
|
180
220
|
};
|
|
181
221
|
|
|
@@ -224,7 +264,6 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
224
264
|
return;
|
|
225
265
|
}
|
|
226
266
|
|
|
227
|
-
//we still need a canvas context for cpu stuff
|
|
228
267
|
if (!this._context2d) {
|
|
229
268
|
this._context2d = this._canvas.getContext('2d', { willReadFrequently: false });
|
|
230
269
|
}
|
|
@@ -235,7 +274,6 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
235
274
|
}
|
|
236
275
|
|
|
237
276
|
if (this._webgl) {
|
|
238
|
-
// make sure we don't have any webgl stuff in the way before we get back to CPU rendering
|
|
239
277
|
this._context.flush();
|
|
240
278
|
}
|
|
241
279
|
|
|
@@ -275,7 +313,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
275
313
|
if (singleSeries.cutoffTime) {
|
|
276
314
|
barParams.cutoffIndex = cutoffIndex;
|
|
277
315
|
barParams.cutoffOpacity = 0.35;
|
|
278
|
-
barParams.originalData =
|
|
316
|
+
barParams.originalData = cutoffData;
|
|
279
317
|
barParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
280
318
|
|
|
281
319
|
const selection = this === this._stateController.rangeGraphRenderer
|
|
@@ -301,11 +339,10 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
301
339
|
inRenderSpaceAreaBottom
|
|
302
340
|
};
|
|
303
341
|
|
|
304
|
-
// add cutoff information for gradient area rendering
|
|
305
342
|
if (singleSeries.cutoffTime) {
|
|
306
343
|
areaParams.cutoffIndex = cutoffIndex;
|
|
307
344
|
areaParams.cutoffOpacity = 0.35;
|
|
308
|
-
areaParams.originalData =
|
|
345
|
+
areaParams.originalData = cutoffData;
|
|
309
346
|
areaParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
310
347
|
areaParams.isPreview = this === this._stateController.rangeGraphRenderer;
|
|
311
348
|
|
|
@@ -344,7 +381,9 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
344
381
|
|
|
345
382
|
let zero = singleSeries.zeroLineY === 'bottom' ?
|
|
346
383
|
this._sizing.renderHeight :
|
|
347
|
-
|
|
384
|
+
singleSeries.zeroLineY !== undefined ?
|
|
385
|
+
(1.0 - ((singleSeries.zeroLineY) - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight :
|
|
386
|
+
this._sizing.renderHeight;
|
|
348
387
|
|
|
349
388
|
const boundsChanged = !this._lastBounds ||
|
|
350
389
|
bounds.minY !== this._lastBounds.minY ||
|
|
@@ -372,21 +411,20 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
372
411
|
inRenderSpaceAreaBottom
|
|
373
412
|
};
|
|
374
413
|
|
|
375
|
-
// add cutoff information for gradient shadow rendering
|
|
376
414
|
if (singleSeries.cutoffTime) {
|
|
377
415
|
shadowParams.cutoffIndex = cutoffIndex;
|
|
378
416
|
shadowParams.cutoffOpacity = 0.35;
|
|
379
|
-
shadowParams.originalData =
|
|
417
|
+
shadowParams.originalData = cutoffData;
|
|
380
418
|
shadowParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
381
419
|
shadowParams.isPreview = this === this._stateController.rangeGraphRenderer;
|
|
382
420
|
|
|
383
421
|
const selection = this === this._stateController.rangeGraphRenderer
|
|
384
422
|
? this._stateController._bounds
|
|
385
423
|
: (this._stateController._selection || this._stateController._bounds);
|
|
386
|
-
shadowParams.selectionBounds = selection;
|
|
424
|
+
shadowParams.selectionBounds = selection || bounds;
|
|
387
425
|
}
|
|
388
426
|
|
|
389
|
-
this._shadowProgram.draw(getIndividualPoints(
|
|
427
|
+
this._shadowProgram.draw(getIndividualPoints(false), shadowParams);
|
|
390
428
|
|
|
391
429
|
if (this._webgl) {
|
|
392
430
|
const gl = this._context;
|
|
@@ -398,7 +436,6 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
398
436
|
|
|
399
437
|
if (singleSeries.zeroLineWidth && singleSeries.zeroLineWidth > 0) {
|
|
400
438
|
if (this._context2d) {
|
|
401
|
-
// in non-webgl mode, use the existing 2d context
|
|
402
439
|
this._context2d.save();
|
|
403
440
|
this._context2d.strokeStyle = singleSeries.zeroLineColor || getColor(singleSeries.color, singleSeries.index, singleSeries.multigrapherSeriesIndex);
|
|
404
441
|
this._context2d.lineWidth = singleSeries.zeroLineWidth;
|
|
@@ -410,7 +447,6 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
410
447
|
this._context2d.stroke();
|
|
411
448
|
this._context2d.restore();
|
|
412
449
|
} else {
|
|
413
|
-
// in webgl mode, we instead create an overlay 2d canvas for the zero line
|
|
414
450
|
if (!this._zeroLineCanvas) {
|
|
415
451
|
this._zeroLineCanvas = document.createElement('canvas');
|
|
416
452
|
this._zeroLineCanvas.style.position = 'absolute';
|
|
@@ -460,20 +496,18 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
460
496
|
return;
|
|
461
497
|
}
|
|
462
498
|
|
|
463
|
-
// Add cutoff information to drawParams for gradient line rendering
|
|
464
499
|
if (singleSeries.cutoffTime) {
|
|
465
500
|
drawParams.cutoffIndex = cutoffIndex;
|
|
466
501
|
drawParams.cutoffOpacity = 0.35;
|
|
467
|
-
drawParams.originalData =
|
|
468
|
-
drawParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
502
|
+
drawParams.originalData = cutoffData;
|
|
503
|
+
drawParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
469
504
|
drawParams.currentBounds = bounds;
|
|
470
|
-
drawParams.isPreview = this === this._stateController.rangeGraphRenderer;
|
|
505
|
+
drawParams.isPreview = this === this._stateController.rangeGraphRenderer;
|
|
471
506
|
|
|
472
|
-
// Always set selectionBounds with fallback
|
|
473
507
|
const selection = this === this._stateController.rangeGraphRenderer
|
|
474
508
|
? this._stateController._bounds
|
|
475
509
|
: (this._stateController._selection || this._stateController._bounds);
|
|
476
|
-
drawParams.selectionBounds = selection;
|
|
510
|
+
drawParams.selectionBounds = selection || bounds;
|
|
477
511
|
}
|
|
478
512
|
|
|
479
513
|
if (this._webgl) {
|
|
@@ -108,7 +108,7 @@ export default class LineProgram {
|
|
|
108
108
|
gl.uniform4f(gl.getUniformLocation(this._program, 'shadowColor'), ...colorToVector(shadowColor));
|
|
109
109
|
|
|
110
110
|
const cutoffX = parameters.cutoffX !== undefined ? parameters.cutoffX : -1.0; // Use parameter or disable
|
|
111
|
-
const cutoffOpacity = parameters.cutoffOpacity !== undefined ? parameters.cutoffOpacity :
|
|
111
|
+
const cutoffOpacity = parameters.cutoffOpacity !== undefined ? parameters.cutoffOpacity : 0.35;
|
|
112
112
|
|
|
113
113
|
gl.uniform1f(gl.getUniformLocation(this._program, 'cutoffX'), cutoffX);
|
|
114
114
|
gl.uniform1f(gl.getUniformLocation(this._program, 'cutoffOpacity'), cutoffOpacity);
|
|
@@ -260,7 +260,7 @@ export default class LineProgram {
|
|
|
260
260
|
if (timeRatio < 0) {
|
|
261
261
|
this.draw(dataInRenderSpace, { ...parameters, renderCutoffGradient: false });
|
|
262
262
|
} else if (timeRatio > 1) {
|
|
263
|
-
const reducedOpacityColor =
|
|
263
|
+
const reducedOpacityColor = applyReducedOpacity(parameters.color, cutoffOpacity);
|
|
264
264
|
this.draw(dataInRenderSpace, {
|
|
265
265
|
...parameters,
|
|
266
266
|
color: reducedOpacityColor,
|
|
@@ -290,7 +290,7 @@ export default class LineProgram {
|
|
|
290
290
|
if (cutoffTime < visibleMinTime) {
|
|
291
291
|
this.draw(dataInRenderSpace, { ...parameters, renderCutoffGradient: false });
|
|
292
292
|
} else if (cutoffTime > visibleMaxTime) {
|
|
293
|
-
const reducedOpacityColor =
|
|
293
|
+
const reducedOpacityColor = applyReducedOpacity(parameters.color, cutoffOpacity);
|
|
294
294
|
this.draw(dataInRenderSpace, {
|
|
295
295
|
...parameters,
|
|
296
296
|
color: reducedOpacityColor,
|
|
@@ -189,6 +189,7 @@ export default class ShadowProgram {
|
|
|
189
189
|
* @param {Object} params - Rendering parameters
|
|
190
190
|
*/
|
|
191
191
|
draw(individualPoints, params) {
|
|
192
|
+
|
|
192
193
|
if (!individualPoints || individualPoints.length < 2) {
|
|
193
194
|
return;
|
|
194
195
|
}
|
|
@@ -211,6 +212,7 @@ export default class ShadowProgram {
|
|
|
211
212
|
const trapezoids = [];
|
|
212
213
|
const { zero, inRenderSpaceAreaBottom } = params;
|
|
213
214
|
|
|
215
|
+
|
|
214
216
|
for (let i = 0; i < individualPoints.length - 1; i++) {
|
|
215
217
|
const [x1, y1] = individualPoints[i];
|
|
216
218
|
const [x2, y2] = individualPoints[i + 1];
|
|
@@ -256,6 +258,7 @@ export default class ShadowProgram {
|
|
|
256
258
|
}
|
|
257
259
|
}
|
|
258
260
|
|
|
261
|
+
|
|
259
262
|
if (trapezoids.length === 0) {
|
|
260
263
|
return;
|
|
261
264
|
}
|
|
@@ -329,6 +332,13 @@ export default class ShadowProgram {
|
|
|
329
332
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, geometry.indices, gl.STATIC_DRAW);
|
|
330
333
|
|
|
331
334
|
gl.drawElements(gl.TRIANGLES, geometry.indices.length, gl.UNSIGNED_INT, 0);
|
|
335
|
+
|
|
336
|
+
const error = gl.getError();
|
|
337
|
+
if (error !== gl.NO_ERROR) {
|
|
338
|
+
console.error('WebGL error in shadow rendering:', error);
|
|
339
|
+
} else {
|
|
340
|
+
//he he he haw
|
|
341
|
+
}
|
|
332
342
|
}
|
|
333
343
|
|
|
334
344
|
/**
|
|
@@ -337,45 +347,56 @@ export default class ShadowProgram {
|
|
|
337
347
|
* @param {Object} params - Rendering parameters with cutoff info
|
|
338
348
|
*/
|
|
339
349
|
drawShadowWithCutoff(individualPoints, params) {
|
|
350
|
+
|
|
340
351
|
const { cutoffIndex, cutoffOpacity, originalData, selectionBounds, zero } =
|
|
341
352
|
params;
|
|
342
353
|
|
|
343
354
|
this._lastIndividualPoints = null;
|
|
344
355
|
this._lastParams = null;
|
|
345
356
|
|
|
357
|
+
// All cutoff data is now in tuple format [x, y] from graph_body_renderer
|
|
346
358
|
let cutoffTime;
|
|
347
|
-
|
|
359
|
+
|
|
360
|
+
if (Array.isArray(originalData[0]) && originalData[0].length === 2) {
|
|
348
361
|
const baseIndex = Math.floor(cutoffIndex);
|
|
349
362
|
const fraction = cutoffIndex - baseIndex;
|
|
350
363
|
|
|
351
364
|
if (fraction === 0 || baseIndex >= originalData.length - 1) {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
cutoffTime =
|
|
355
|
-
cutoffDate instanceof Date ? cutoffDate.getTime() : cutoffDate;
|
|
365
|
+
const cutoffItem = originalData[Math.min(baseIndex, originalData.length - 1)];
|
|
366
|
+
const cutoffDate = cutoffItem[0];
|
|
367
|
+
cutoffTime = cutoffDate instanceof Date ? cutoffDate.getTime() : cutoffDate;
|
|
356
368
|
} else {
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
369
|
+
const currentItem = originalData[baseIndex];
|
|
370
|
+
const nextItem = originalData[baseIndex + 1];
|
|
371
|
+
const currentDate = currentItem[0];
|
|
372
|
+
const nextDate = nextItem[0];
|
|
373
|
+
const currentTime = currentDate instanceof Date ? currentDate.getTime() : currentDate;
|
|
374
|
+
const nextTime = nextDate instanceof Date ? nextDate.getTime() : nextDate;
|
|
363
375
|
cutoffTime = currentTime + fraction * (nextTime - currentTime);
|
|
364
376
|
}
|
|
365
377
|
} else {
|
|
366
378
|
cutoffTime = cutoffIndex;
|
|
367
379
|
}
|
|
368
380
|
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
381
|
+
const visibleBounds = params.selectionBounds;
|
|
382
|
+
let firstTime, lastTime;
|
|
383
|
+
|
|
384
|
+
if (visibleBounds && visibleBounds.minX !== undefined && visibleBounds.maxX !== undefined) {
|
|
385
|
+
firstTime = visibleBounds.minX instanceof Date ? visibleBounds.minX.getTime() : visibleBounds.minX;
|
|
386
|
+
lastTime = visibleBounds.maxX instanceof Date ? visibleBounds.maxX.getTime() : visibleBounds.maxX;
|
|
387
|
+
} else {
|
|
388
|
+
const firstItem = originalData[0];
|
|
389
|
+
const lastItem = originalData[originalData.length - 1];
|
|
390
|
+
const firstX = firstItem[0];
|
|
391
|
+
const lastX = lastItem[0];
|
|
392
|
+
|
|
393
|
+
firstTime = firstX instanceof Date ? firstX.getTime() : firstX;
|
|
394
|
+
lastTime = lastX instanceof Date ? lastX.getTime() : lastX;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const timeDiff = cutoffTime - firstTime;
|
|
398
|
+
const totalTime = lastTime - firstTime;
|
|
399
|
+
const timeRatio = timeDiff / totalTime;
|
|
379
400
|
|
|
380
401
|
if (timeRatio < 0) {
|
|
381
402
|
this.draw(individualPoints, { ...params, renderCutoffGradient: false });
|
|
@@ -392,7 +413,7 @@ export default class ShadowProgram {
|
|
|
392
413
|
} else {
|
|
393
414
|
this.drawSplitShadowTrapezoids(
|
|
394
415
|
individualPoints,
|
|
395
|
-
params,
|
|
416
|
+
{ ...params, selectionBounds: params.selectionBounds },
|
|
396
417
|
timeRatio,
|
|
397
418
|
cutoffTime
|
|
398
419
|
);
|
|
@@ -407,41 +428,41 @@ export default class ShadowProgram {
|
|
|
407
428
|
* @param {number} cutoffTime - Cutoff timestamp
|
|
408
429
|
*/
|
|
409
430
|
drawSplitShadowTrapezoids(individualPoints, params, timeRatio, cutoffTime) {
|
|
410
|
-
const { zero, cutoffOpacity } = params;
|
|
431
|
+
const { zero, cutoffOpacity, selectionBounds } = params;
|
|
411
432
|
const gl = this._gl;
|
|
412
433
|
|
|
413
|
-
const
|
|
414
|
-
const
|
|
415
|
-
const fraction = renderCutoffIndex - splitIndex;
|
|
416
|
-
|
|
417
|
-
let ghostPoint = null;
|
|
418
|
-
if (
|
|
419
|
-
splitIndex >= 0 &&
|
|
420
|
-
splitIndex < individualPoints.length - 1 &&
|
|
421
|
-
fraction > 0
|
|
422
|
-
) {
|
|
423
|
-
const beforePoint = individualPoints[splitIndex];
|
|
424
|
-
const afterPoint = individualPoints[splitIndex + 1];
|
|
425
|
-
ghostPoint = [
|
|
426
|
-
beforePoint[0] + fraction * (afterPoint[0] - beforePoint[0]),
|
|
427
|
-
beforePoint[1] + fraction * (afterPoint[1] - beforePoint[1]),
|
|
428
|
-
];
|
|
429
|
-
}
|
|
434
|
+
const renderWidth = gl.canvas.width;
|
|
435
|
+
const cutoffPixelX = timeRatio * renderWidth;
|
|
430
436
|
|
|
431
437
|
const preCutoffPoints = [];
|
|
432
|
-
for (let i = 0; i <= splitIndex && i < individualPoints.length; i++) {
|
|
433
|
-
preCutoffPoints.push(individualPoints[i]);
|
|
434
|
-
}
|
|
435
|
-
if (ghostPoint && splitIndex < individualPoints.length - 1) {
|
|
436
|
-
preCutoffPoints.push(ghostPoint);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
438
|
const postCutoffPoints = [];
|
|
440
|
-
|
|
441
|
-
|
|
439
|
+
|
|
440
|
+
for (let i = 0; i < individualPoints.length; i++) {
|
|
441
|
+
const [pixelX, pixelY] = individualPoints[i];
|
|
442
|
+
|
|
443
|
+
if (pixelX < cutoffPixelX) {
|
|
444
|
+
preCutoffPoints.push(individualPoints[i]);
|
|
445
|
+
} else {
|
|
446
|
+
postCutoffPoints.push(individualPoints[i]);
|
|
447
|
+
}
|
|
442
448
|
}
|
|
443
|
-
|
|
444
|
-
|
|
449
|
+
|
|
450
|
+
let ghostPoint = null;
|
|
451
|
+
if (preCutoffPoints.length > 0 && postCutoffPoints.length > 0) {
|
|
452
|
+
const lastPrePoint = preCutoffPoints[preCutoffPoints.length - 1];
|
|
453
|
+
const firstPostPoint = postCutoffPoints[0];
|
|
454
|
+
|
|
455
|
+
const [x1, y1] = lastPrePoint;
|
|
456
|
+
const [x2, y2] = firstPostPoint;
|
|
457
|
+
|
|
458
|
+
if (x2 !== x1) {
|
|
459
|
+
const interpolationRatio = (cutoffPixelX - x1) / (x2 - x1);
|
|
460
|
+
const ghostY = y1 + interpolationRatio * (y2 - y1);
|
|
461
|
+
ghostPoint = [cutoffPixelX, ghostY];
|
|
462
|
+
|
|
463
|
+
preCutoffPoints.push(ghostPoint);
|
|
464
|
+
postCutoffPoints.unshift(ghostPoint);
|
|
465
|
+
}
|
|
445
466
|
}
|
|
446
467
|
|
|
447
468
|
if (preCutoffPoints.length >= 2) {
|
|
@@ -467,6 +488,7 @@ export default class ShadowProgram {
|
|
|
467
488
|
gradient: translucentGradient,
|
|
468
489
|
renderCutoffGradient: false,
|
|
469
490
|
});
|
|
491
|
+
} else {
|
|
470
492
|
}
|
|
471
493
|
|
|
472
494
|
if (postCutoffPoints.length >= 2) {
|
|
@@ -474,6 +496,7 @@ export default class ShadowProgram {
|
|
|
474
496
|
...params,
|
|
475
497
|
renderCutoffGradient: false,
|
|
476
498
|
});
|
|
499
|
+
} else {
|
|
477
500
|
}
|
|
478
501
|
}
|
|
479
502
|
}
|