@windborne/grapher 1.0.29 → 1.0.30
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/readme.md +1 -1
- package/src/helpers/colors.js +12 -0
- package/src/helpers/custom_prop_types.js +2 -1
- package/src/index.d.ts +2 -1
- package/src/renderer/draw_area.js +49 -70
- package/src/renderer/draw_line.js +17 -11
- package/src/renderer/graph_body_renderer.js +50 -13
- package/src/renderer/line_program.js +12 -12
- package/src/renderer/shadow_program.js +5 -0
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -214,7 +214,7 @@ Grapher supports multiple data formats within a series:
|
|
|
214
214
|
|
|
215
215
|
| Prop | Type | Required | Description |
|
|
216
216
|
|------|------|----------|-------------|
|
|
217
|
-
| **x** | `number` | **✓** | X-coordinate position where the line should appear. |
|
|
217
|
+
| **x** | `number \| Date` | **✓** | X-coordinate position where the line should appear. Can be a numeric value or a Date object. |
|
|
218
218
|
| color | `string` | ✗ | Optional line color. |
|
|
219
219
|
| lineTop | `number` | ✗ | Optional value to specify the top position of the line. |
|
|
220
220
|
| width | `number` | ✗ | Optional line width. |
|
package/src/helpers/colors.js
CHANGED
|
@@ -91,3 +91,15 @@ export function applyReducedOpacityToGradient(gradient, opacityFactor) {
|
|
|
91
91
|
return stop;
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Creates a default gradient from a color at half opacity
|
|
97
|
+
* @param {string} color
|
|
98
|
+
* @returns {Array<[number, string]>}
|
|
99
|
+
*/
|
|
100
|
+
export function createDefaultGradient(color) {
|
|
101
|
+
if (!color) return [[0, 'transparent'], [1, 'transparent']];
|
|
102
|
+
|
|
103
|
+
const halfOpacityColor = applyReducedOpacity(color, 0.5);
|
|
104
|
+
return [[0, halfOpacityColor], [1, halfOpacityColor]];
|
|
105
|
+
}
|
|
@@ -65,6 +65,7 @@ const SingleSeries = PropTypes.shape({
|
|
|
65
65
|
background: PropTypes.object,
|
|
66
66
|
hideFromKey: PropTypes.bool,
|
|
67
67
|
showIndividualPoints: PropTypes.bool,
|
|
68
|
+
minPointSpacing: PropTypes.number,
|
|
68
69
|
rendering: PropTypes.oneOf(['line', 'bar', 'area', 'shadow']), // defaults to line
|
|
69
70
|
negativeColor: PropTypes.string, // only applies to bar
|
|
70
71
|
gradient: PropTypes.array, // only applies to area
|
|
@@ -139,7 +140,7 @@ const DraggablePoint = PropTypes.shape({
|
|
|
139
140
|
const DraggablePoints = PropTypes.arrayOf(DraggablePoint);
|
|
140
141
|
|
|
141
142
|
const VerticalLine = PropTypes.shape({
|
|
142
|
-
x: PropTypes.number.isRequired,
|
|
143
|
+
x: PropTypes.oneOfType([PropTypes.number, PropTypes.instanceOf(Date)]).isRequired,
|
|
143
144
|
color: PropTypes.string,
|
|
144
145
|
lineTop: PropTypes.number,
|
|
145
146
|
width: PropTypes.number,
|
package/src/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface SeriesData {
|
|
|
24
24
|
background?: object;
|
|
25
25
|
hideFromKey?: boolean;
|
|
26
26
|
showIndividualPoints?: boolean;
|
|
27
|
+
minPointSpacing?: number;
|
|
27
28
|
rendering?: 'line' | 'bar' | 'area' | 'shadow';
|
|
28
29
|
negativeColor?: string;
|
|
29
30
|
zeroLineWidth?: number;
|
|
@@ -80,7 +81,7 @@ export interface DraggablePoint {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
export interface VerticalLine {
|
|
83
|
-
x: number;
|
|
84
|
+
x: number | Date;
|
|
84
85
|
color?: string;
|
|
85
86
|
lineTop?: number;
|
|
86
87
|
width?: number;
|
|
@@ -220,7 +220,7 @@ export default function drawArea(
|
|
|
220
220
|
});
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
if (showIndividualPoints) {
|
|
223
|
+
if (showIndividualPoints && !renderCutoffGradient) {
|
|
224
224
|
context.fillStyle = color;
|
|
225
225
|
|
|
226
226
|
for (let [x, y] of individualPoints) {
|
|
@@ -312,14 +312,15 @@ function drawAreaWithCutoff(
|
|
|
312
312
|
cutoffTime = cutoffIndex;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
originalData[originalData.
|
|
321
|
-
|
|
322
|
-
: originalData[originalData.length - 1][0];
|
|
315
|
+
let firstTime, lastTime;
|
|
316
|
+
if (isPreview && selectionBounds) {
|
|
317
|
+
firstTime = selectionBounds.minX instanceof Date ? selectionBounds.minX.getTime() : selectionBounds.minX;
|
|
318
|
+
lastTime = selectionBounds.maxX instanceof Date ? selectionBounds.maxX.getTime() : selectionBounds.maxX;
|
|
319
|
+
} else {
|
|
320
|
+
firstTime = originalData[0][0] instanceof Date ? originalData[0][0].getTime() : originalData[0][0];
|
|
321
|
+
lastTime = originalData[originalData.length - 1][0] instanceof Date ?
|
|
322
|
+
originalData[originalData.length - 1][0].getTime() : originalData[originalData.length - 1][0];
|
|
323
|
+
}
|
|
323
324
|
|
|
324
325
|
const timeRatio = (cutoffTime - firstTime) / (lastTime - firstTime);
|
|
325
326
|
|
|
@@ -657,7 +658,7 @@ function drawAreaWithCutoff(
|
|
|
657
658
|
}
|
|
658
659
|
|
|
659
660
|
// draw outline lines with cutoff
|
|
660
|
-
if (timeRatio >= 0 && timeRatio <= 1) {
|
|
661
|
+
if (timeRatio >= 0 && timeRatio <= 1 && !isPreview) {
|
|
661
662
|
if (selectionBounds) {
|
|
662
663
|
const visibleMinTime =
|
|
663
664
|
selectionBounds.minX instanceof Date
|
|
@@ -719,7 +720,7 @@ function drawAreaWithCutoff(
|
|
|
719
720
|
highlighted,
|
|
720
721
|
});
|
|
721
722
|
}
|
|
722
|
-
} else {
|
|
723
|
+
} else if (!isPreview) {
|
|
723
724
|
// draw lines normally without cutoff
|
|
724
725
|
drawLinesNormally(linePaths, {
|
|
725
726
|
color,
|
|
@@ -744,7 +745,7 @@ function drawAreaWithCutoff(
|
|
|
744
745
|
});
|
|
745
746
|
}
|
|
746
747
|
|
|
747
|
-
if (showIndividualPoints) {
|
|
748
|
+
if (showIndividualPoints && !isPreview) {
|
|
748
749
|
if (timeRatio >= 0 && timeRatio <= 1) {
|
|
749
750
|
if (selectionBounds) {
|
|
750
751
|
const visibleMinTime =
|
|
@@ -1072,72 +1073,49 @@ function drawLinesWithCutoff(
|
|
|
1072
1073
|
}
|
|
1073
1074
|
width *= DPI_INCREASE;
|
|
1074
1075
|
|
|
1075
|
-
|
|
1076
|
-
const pathLengths = [];
|
|
1077
|
-
|
|
1078
|
-
for (let path of linePaths) {
|
|
1079
|
-
if (path.length > 0) {
|
|
1080
|
-
pathLengths.push(path.length);
|
|
1081
|
-
totalLength += path.length;
|
|
1082
|
-
} else {
|
|
1083
|
-
pathLengths.push(0);
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
if (totalLength === 0) return;
|
|
1088
|
-
|
|
1089
|
-
const globalCutoffIndex = timeRatio * totalLength;
|
|
1090
|
-
|
|
1091
|
-
let currentIndex = 0;
|
|
1092
|
-
let targetPathIndex = -1;
|
|
1093
|
-
let cutoffIndexInPath = 0;
|
|
1094
|
-
|
|
1095
|
-
for (let i = 0; i < pathLengths.length; i++) {
|
|
1096
|
-
if (pathLengths[i] === 0) continue;
|
|
1097
|
-
|
|
1098
|
-
if (globalCutoffIndex <= currentIndex + pathLengths[i]) {
|
|
1099
|
-
targetPathIndex = i;
|
|
1100
|
-
cutoffIndexInPath = globalCutoffIndex - currentIndex;
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1103
|
-
currentIndex += pathLengths[i];
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1076
|
+
const cutoffPixelX = timeRatio * context.canvas.width;
|
|
1106
1077
|
const preCutoffPaths = [];
|
|
1107
1078
|
const postCutoffPaths = [];
|
|
1108
|
-
let ghostPoint = null;
|
|
1109
1079
|
|
|
1110
|
-
for (let
|
|
1111
|
-
const path = linePaths[i];
|
|
1080
|
+
for (let path of linePaths) {
|
|
1112
1081
|
if (!path.length) continue;
|
|
1113
1082
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
} else if (i === targetPathIndex) {
|
|
1119
|
-
const splitIndex = Math.floor(cutoffIndexInPath);
|
|
1120
|
-
const fraction = cutoffIndexInPath - splitIndex;
|
|
1121
|
-
|
|
1122
|
-
if (splitIndex < path.length - 1 && fraction > 0) {
|
|
1123
|
-
const [x1, y1] = path[splitIndex];
|
|
1124
|
-
const [x2, y2] = path[splitIndex + 1];
|
|
1125
|
-
ghostPoint = [x1 + fraction * (x2 - x1), y1 + fraction * (y2 - y1)];
|
|
1126
|
-
}
|
|
1083
|
+
const prePath = [];
|
|
1084
|
+
const postPath = [];
|
|
1085
|
+
let ghostPoint = null;
|
|
1086
|
+
let splitIndex = -1;
|
|
1127
1087
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1088
|
+
for (let i = 0; i < path.length; i++) {
|
|
1089
|
+
const [x, y] = path[i];
|
|
1090
|
+
|
|
1091
|
+
if (x < cutoffPixelX) {
|
|
1092
|
+
prePath.push([x, y]);
|
|
1093
|
+
splitIndex = i;
|
|
1094
|
+
} else {
|
|
1095
|
+
postPath.push([x, y]);
|
|
1132
1096
|
}
|
|
1097
|
+
}
|
|
1133
1098
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1099
|
+
if (prePath.length > 0 && postPath.length > 0) {
|
|
1100
|
+
const lastPrePoint = prePath[prePath.length - 1];
|
|
1101
|
+
const firstPostPoint = postPath[0];
|
|
1102
|
+
const [x1, y1] = lastPrePoint;
|
|
1103
|
+
const [x2, y2] = firstPostPoint;
|
|
1104
|
+
|
|
1105
|
+
if (x2 !== x1) {
|
|
1106
|
+
const fraction = (cutoffPixelX - x1) / (x2 - x1);
|
|
1107
|
+
ghostPoint = [cutoffPixelX, y1 + fraction * (y2 - y1)];
|
|
1108
|
+
prePath.push(ghostPoint);
|
|
1109
|
+
postPath.unshift(ghostPoint);
|
|
1139
1110
|
}
|
|
1140
1111
|
}
|
|
1112
|
+
|
|
1113
|
+
if (prePath.length > 0) {
|
|
1114
|
+
preCutoffPaths.push(prePath);
|
|
1115
|
+
}
|
|
1116
|
+
if (postPath.length > 0) {
|
|
1117
|
+
postCutoffPaths.push(postPath);
|
|
1118
|
+
}
|
|
1141
1119
|
}
|
|
1142
1120
|
|
|
1143
1121
|
if (preCutoffPaths.length > 0) {
|
|
@@ -1200,12 +1178,13 @@ function drawPointsWithCutoffByRatio(
|
|
|
1200
1178
|
return;
|
|
1201
1179
|
}
|
|
1202
1180
|
|
|
1203
|
-
const
|
|
1181
|
+
const canvasWidth = context.canvas.width;
|
|
1182
|
+
const cutoffPixelX = timeRatio * canvasWidth;
|
|
1204
1183
|
|
|
1205
1184
|
for (let i = 0; i < individualPoints.length; i++) {
|
|
1206
1185
|
const [x, y] = individualPoints[i];
|
|
1207
1186
|
|
|
1208
|
-
const isBeforeCutoff =
|
|
1187
|
+
const isBeforeCutoff = x < cutoffPixelX;
|
|
1209
1188
|
|
|
1210
1189
|
let pointColor = color;
|
|
1211
1190
|
if (isBeforeCutoff) {
|
|
@@ -3,7 +3,7 @@ import pathsFrom from './paths_from';
|
|
|
3
3
|
import { applyReducedOpacity } from "../helpers/colors";
|
|
4
4
|
|
|
5
5
|
export default function drawLine(dataInRenderSpace, {
|
|
6
|
-
color, width=1, context, shadowColor='black', shadowBlur=5, dashed=false, dashPattern=null, highlighted=false, showIndividualPoints=false, getIndividualPoints, getRanges, cutoffIndex, cutoffOpacity, originalData, renderCutoffGradient, currentBounds, selectionBounds, rendering, isPreview
|
|
6
|
+
color, width=1, context, shadowColor='black', shadowBlur=5, dashed=false, dashPattern=null, highlighted=false, showIndividualPoints=false, pointRadius, getIndividualPoints, getRanges, cutoffIndex, cutoffOpacity, originalData, renderCutoffGradient, currentBounds, selectionBounds, rendering, isPreview
|
|
7
7
|
}) {
|
|
8
8
|
if (!context) {
|
|
9
9
|
console.error("Canvas context is null in drawLine");
|
|
@@ -340,16 +340,22 @@ export default function drawLine(dataInRenderSpace, {
|
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
if (isPreview) {
|
|
343
|
-
const
|
|
344
|
-
const
|
|
345
|
-
originalData[originalData.length - 1][0].getTime() : originalData[originalData.length - 1][0];
|
|
346
|
-
const timeRatio = (cutoffTime - firstTime) / (lastTime - firstTime);
|
|
343
|
+
const visibleMinTime = selectionBounds.minX instanceof Date ? selectionBounds.minX.getTime() : selectionBounds.minX;
|
|
344
|
+
const visibleMaxTime = selectionBounds.maxX instanceof Date ? selectionBounds.maxX.getTime() : selectionBounds.maxX;
|
|
347
345
|
|
|
348
346
|
for (let i = 0; i < individualPoints.length; i++) {
|
|
349
347
|
const [x, y] = individualPoints[i];
|
|
350
348
|
|
|
351
|
-
|
|
352
|
-
|
|
349
|
+
let isBeforeCutoff = false;
|
|
350
|
+
if (cutoffTime < visibleMinTime) {
|
|
351
|
+
isBeforeCutoff = false;
|
|
352
|
+
} else if (cutoffTime > visibleMaxTime) {
|
|
353
|
+
isBeforeCutoff = (rendering !== 'shadow');
|
|
354
|
+
} else {
|
|
355
|
+
const visibleCutoffRatio = (cutoffTime - visibleMinTime) / (visibleMaxTime - visibleMinTime);
|
|
356
|
+
const cutoffPixelX = visibleCutoffRatio * context.canvas.width;
|
|
357
|
+
isBeforeCutoff = x < cutoffPixelX;
|
|
358
|
+
}
|
|
353
359
|
|
|
354
360
|
if (isBeforeCutoff) {
|
|
355
361
|
const reducedOpacityColor = applyReducedOpacity(color, cutoffOpacity);
|
|
@@ -359,7 +365,7 @@ export default function drawLine(dataInRenderSpace, {
|
|
|
359
365
|
}
|
|
360
366
|
|
|
361
367
|
context.beginPath();
|
|
362
|
-
context.arc(x, y,
|
|
368
|
+
context.arc(x, y, pointRadius || 8, 0, 2 * Math.PI, false);
|
|
363
369
|
context.fill();
|
|
364
370
|
}
|
|
365
371
|
} else if (!selectionBounds) {
|
|
@@ -367,7 +373,7 @@ export default function drawLine(dataInRenderSpace, {
|
|
|
367
373
|
const [x, y] = individualPoints[i];
|
|
368
374
|
context.fillStyle = color;
|
|
369
375
|
context.beginPath();
|
|
370
|
-
context.arc(x, y,
|
|
376
|
+
context.arc(x, y, pointRadius || 8, 0, 2 * Math.PI, false);
|
|
371
377
|
context.fill();
|
|
372
378
|
}
|
|
373
379
|
} else {
|
|
@@ -396,7 +402,7 @@ export default function drawLine(dataInRenderSpace, {
|
|
|
396
402
|
}
|
|
397
403
|
|
|
398
404
|
context.beginPath();
|
|
399
|
-
context.arc(x, y,
|
|
405
|
+
context.arc(x, y, pointRadius || 8, 0, 2 * Math.PI, false);
|
|
400
406
|
context.fill();
|
|
401
407
|
}
|
|
402
408
|
}
|
|
@@ -405,7 +411,7 @@ export default function drawLine(dataInRenderSpace, {
|
|
|
405
411
|
const [x, y] = individualPoints[i];
|
|
406
412
|
context.fillStyle = color;
|
|
407
413
|
context.beginPath();
|
|
408
|
-
context.arc(x, y,
|
|
414
|
+
context.arc(x, y, pointRadius || 8, 0, 2 * Math.PI, false);
|
|
409
415
|
context.fill();
|
|
410
416
|
}
|
|
411
417
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Eventable from '../eventable';
|
|
2
|
-
import getColor from '../helpers/colors';
|
|
2
|
+
import getColor, { createDefaultGradient } from '../helpers/colors';
|
|
3
3
|
import inferType from '../state/infer_type';
|
|
4
4
|
import BackgroundProgram from './background_program.js';
|
|
5
5
|
import drawArea from './draw_area';
|
|
@@ -161,7 +161,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
const getIndividualPoints = (useDataSpace, includeBeyondBounds = false) => {
|
|
164
|
-
if (!useDataSpace && inRenderSpace && inRenderSpace.yValues) {
|
|
164
|
+
if (!useDataSpace && inRenderSpace && inRenderSpace.yValues && !showIndividualPoints) {
|
|
165
165
|
if (!bounds) {
|
|
166
166
|
bounds = singleSeries.axis.currentBounds;
|
|
167
167
|
}
|
|
@@ -188,6 +188,21 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
188
188
|
return getIndividualPoints(true, includeBeyondBounds);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
// Apply minPointSpacing if specified
|
|
192
|
+
if (singleSeries.minPointSpacing && individualPoints.length > 1) {
|
|
193
|
+
const spacedPoints = [];
|
|
194
|
+
let lastX = -Infinity;
|
|
195
|
+
|
|
196
|
+
for (const [x, y] of individualPoints) {
|
|
197
|
+
if (x - lastX >= singleSeries.minPointSpacing) {
|
|
198
|
+
spacedPoints.push([x, y]);
|
|
199
|
+
lastX = x;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return spacedPoints;
|
|
204
|
+
}
|
|
205
|
+
|
|
191
206
|
return individualPoints;
|
|
192
207
|
}
|
|
193
208
|
|
|
@@ -255,6 +270,19 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
255
270
|
individualPoints.unshift([beforeXCoord, beforeYCoord]);
|
|
256
271
|
}
|
|
257
272
|
|
|
273
|
+
if (singleSeries.minPointSpacing && individualPoints.length > 1) {
|
|
274
|
+
const spacedPoints = [];
|
|
275
|
+
let lastX = -Infinity;
|
|
276
|
+
|
|
277
|
+
for (const [x, y] of individualPoints) {
|
|
278
|
+
if (x - lastX >= singleSeries.minPointSpacing) {
|
|
279
|
+
spacedPoints.push([x, y]);
|
|
280
|
+
lastX = x;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return spacedPoints;
|
|
285
|
+
}
|
|
258
286
|
return individualPoints;
|
|
259
287
|
};
|
|
260
288
|
|
|
@@ -351,7 +379,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
351
379
|
|
|
352
380
|
if (singleSeries.cutoffTime) {
|
|
353
381
|
barParams.cutoffIndex = cutoffIndex;
|
|
354
|
-
barParams.cutoffOpacity = 0.35;
|
|
382
|
+
barParams.cutoffOpacity = singleSeries.cutoffOpacity !== undefined ? singleSeries.cutoffOpacity : 0.35;
|
|
355
383
|
barParams.originalData = cutoffData;
|
|
356
384
|
barParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
357
385
|
|
|
@@ -380,7 +408,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
380
408
|
|
|
381
409
|
if (singleSeries.cutoffTime) {
|
|
382
410
|
areaParams.cutoffIndex = cutoffIndex;
|
|
383
|
-
areaParams.cutoffOpacity = 0.35;
|
|
411
|
+
areaParams.cutoffOpacity = singleSeries.cutoffOpacity !== undefined ? singleSeries.cutoffOpacity : 0.35;
|
|
384
412
|
areaParams.originalData = cutoffData;
|
|
385
413
|
areaParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
386
414
|
areaParams.isPreview = this === this._stateController.rangeGraphRenderer;
|
|
@@ -418,11 +446,18 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
418
446
|
bounds = singleSeries.axis.currentBounds;
|
|
419
447
|
}
|
|
420
448
|
|
|
421
|
-
let zero
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
449
|
+
let zero;
|
|
450
|
+
if (singleSeries.zeroLineY === 'bottom') {
|
|
451
|
+
zero = this._sizing.renderHeight;
|
|
452
|
+
} else if (singleSeries.zeroLineY !== undefined) {
|
|
453
|
+
zero = (1.0 - ((singleSeries.zeroLineY) - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight;
|
|
454
|
+
} else {
|
|
455
|
+
if (bounds.minY <= 0 && bounds.maxY >= 0) {
|
|
456
|
+
zero = (1.0 - (0 - bounds.minY) / (bounds.maxY - bounds.minY)) * this._sizing.renderHeight;
|
|
457
|
+
} else {
|
|
458
|
+
zero = this._sizing.renderHeight;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
426
461
|
|
|
427
462
|
const boundsChanged = !this._lastBounds ||
|
|
428
463
|
bounds.minY !== this._lastBounds.minY ||
|
|
@@ -442,9 +477,10 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
442
477
|
zero = 0;
|
|
443
478
|
}
|
|
444
479
|
|
|
480
|
+
const shadowColor = getColor(singleSeries.color, singleSeries.index, singleSeries.multigrapherSeriesIndex);
|
|
445
481
|
let shadowParams = {
|
|
446
|
-
color:
|
|
447
|
-
gradient: singleSeries.gradient,
|
|
482
|
+
color: shadowColor,
|
|
483
|
+
gradient: singleSeries.gradient || createDefaultGradient(shadowColor),
|
|
448
484
|
zero,
|
|
449
485
|
sizing: this._sizing,
|
|
450
486
|
inRenderSpaceAreaBottom
|
|
@@ -452,7 +488,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
452
488
|
|
|
453
489
|
if (singleSeries.cutoffTime) {
|
|
454
490
|
shadowParams.cutoffIndex = cutoffIndex;
|
|
455
|
-
shadowParams.cutoffOpacity = 0.35;
|
|
491
|
+
shadowParams.cutoffOpacity = singleSeries.cutoffOpacity !== undefined ? singleSeries.cutoffOpacity : 0.35;
|
|
456
492
|
shadowParams.originalData = cutoffData;
|
|
457
493
|
shadowParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
458
494
|
shadowParams.isPreview = this === this._stateController.rangeGraphRenderer;
|
|
@@ -524,6 +560,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
524
560
|
dashPattern: singleSeries.dashPattern,
|
|
525
561
|
highlighted,
|
|
526
562
|
showIndividualPoints: shouldShowIndividualPoints,
|
|
563
|
+
pointRadius: singleSeries.pointRadius,
|
|
527
564
|
getIndividualPoints,
|
|
528
565
|
getRanges: singleSeries.rangeKey ? getRanges : null,
|
|
529
566
|
rendering: singleSeries.rendering // Pass rendering type for all charts
|
|
@@ -536,7 +573,7 @@ export default class GraphBodyRenderer extends Eventable {
|
|
|
536
573
|
|
|
537
574
|
if (singleSeries.cutoffTime) {
|
|
538
575
|
drawParams.cutoffIndex = cutoffIndex;
|
|
539
|
-
drawParams.cutoffOpacity = 0.35;
|
|
576
|
+
drawParams.cutoffOpacity = singleSeries.cutoffOpacity !== undefined ? singleSeries.cutoffOpacity : 0.35;
|
|
540
577
|
drawParams.originalData = cutoffData;
|
|
541
578
|
drawParams.renderCutoffGradient = cutoffIndex >= 0;
|
|
542
579
|
drawParams.currentBounds = bounds;
|
|
@@ -122,7 +122,8 @@ export default class LineProgram {
|
|
|
122
122
|
|
|
123
123
|
gl.uniform1f(gl.getUniformLocation(this._circleProgram, 'width'), width);
|
|
124
124
|
gl.uniform1f(gl.getUniformLocation(this._circleProgram, 'height'), height);
|
|
125
|
-
|
|
125
|
+
const pointSize = parameters.pointRadius ? parameters.pointRadius * 2 * DPI_INCREASE : 2*(thickness+6);
|
|
126
|
+
gl.uniform1f(gl.getUniformLocation(this._circleProgram, 'pointSize'), pointSize);
|
|
126
127
|
|
|
127
128
|
const individualPoints = parameters.getIndividualPoints();
|
|
128
129
|
|
|
@@ -150,14 +151,14 @@ export default class LineProgram {
|
|
|
150
151
|
const postCutoffPoints = [];
|
|
151
152
|
|
|
152
153
|
if (parameters.isPreview) {
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
const
|
|
154
|
+
const visibleMinTime = parameters.selectionBounds.minX instanceof Date ? parameters.selectionBounds.minX.getTime() : parameters.selectionBounds.minX;
|
|
155
|
+
const visibleMaxTime = parameters.selectionBounds.maxX instanceof Date ? parameters.selectionBounds.maxX.getTime() : parameters.selectionBounds.maxX;
|
|
156
|
+
const timeRatio = (cutoffTime - visibleMinTime) / (visibleMaxTime - visibleMinTime);
|
|
157
|
+
const cutoffPixelX = timeRatio * width;
|
|
157
158
|
|
|
158
159
|
for (let i = 0; i < individualPoints.length; i++) {
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
160
|
+
const [pixelX, pixelY] = individualPoints[i];
|
|
161
|
+
if (pixelX < cutoffPixelX) {
|
|
161
162
|
preCutoffPoints.push(individualPoints[i]);
|
|
162
163
|
} else {
|
|
163
164
|
postCutoffPoints.push(individualPoints[i]);
|
|
@@ -252,10 +253,10 @@ export default class LineProgram {
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
if (parameters.isPreview) {
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
const timeRatio = (cutoffTime -
|
|
256
|
+
const gl = this._gl;
|
|
257
|
+
const visibleMinTime = selectionBounds.minX instanceof Date ? selectionBounds.minX.getTime() : selectionBounds.minX;
|
|
258
|
+
const visibleMaxTime = selectionBounds.maxX instanceof Date ? selectionBounds.maxX.getTime() : selectionBounds.maxX;
|
|
259
|
+
const timeRatio = (cutoffTime - visibleMinTime) / (visibleMaxTime - visibleMinTime);
|
|
259
260
|
|
|
260
261
|
if (timeRatio < 0) {
|
|
261
262
|
this.draw(dataInRenderSpace, { ...parameters, renderCutoffGradient: false });
|
|
@@ -267,7 +268,6 @@ export default class LineProgram {
|
|
|
267
268
|
renderCutoffGradient: false
|
|
268
269
|
});
|
|
269
270
|
} else {
|
|
270
|
-
const gl = this._gl;
|
|
271
271
|
gl.enable(gl.BLEND);
|
|
272
272
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
273
273
|
|
|
@@ -422,9 +422,14 @@ export default class ShadowProgram {
|
|
|
422
422
|
params.color,
|
|
423
423
|
cutoffOpacity
|
|
424
424
|
);
|
|
425
|
+
const translucentGradient = applyReducedOpacityToGradient(
|
|
426
|
+
params.gradient,
|
|
427
|
+
cutoffOpacity
|
|
428
|
+
);
|
|
425
429
|
this.draw(individualPoints, {
|
|
426
430
|
...params,
|
|
427
431
|
color: reducedOpacityColor,
|
|
432
|
+
gradient: translucentGradient,
|
|
428
433
|
renderCutoffGradient: false,
|
|
429
434
|
});
|
|
430
435
|
} else {
|