@windborne/grapher 1.0.22 → 1.0.24
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/26b23c7580ea3345d644.wasm +0 -0
- package/dist/744.bundle.cjs +2 -1
- package/dist/744.bundle.cjs.map +1 -0
- package/dist/744.bundle.esm.js +2 -1
- package/dist/744.bundle.esm.js.map +1 -0
- 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/components/graph_body.jsx +41 -1
- package/src/components/range_graph.jsx +70 -22
- package/src/components/x_axis.jsx +139 -21
- package/src/components/y_axis.jsx +0 -5
- package/src/grapher.jsx +4 -3
- package/src/grapher.scss +84 -43
- package/src/helpers/color_to_vector.js +6 -1
- package/src/helpers/colors.js +82 -16
- package/src/helpers/custom_prop_types.js +2 -1
- package/src/helpers/place_grid.js +219 -0
- package/src/index.d.ts +3 -2
- package/src/renderer/create_gl_program.js +11 -3
- package/src/renderer/draw_area.js +1161 -102
- package/src/renderer/draw_background.js +5 -0
- package/src/renderer/draw_bars.js +100 -11
- package/src/renderer/draw_line.js +338 -38
- package/src/renderer/draw_zero_line.js +5 -0
- package/src/renderer/extract_vertices.js +1 -1
- package/src/renderer/graph_body_renderer.js +278 -17
- package/src/renderer/line.frag +16 -1
- package/src/renderer/line_program.js +200 -10
- package/src/renderer/shadow.frag +98 -0
- package/src/renderer/shadow.vert +20 -0
- package/src/renderer/shadow_program.js +479 -0
- package/src/rust/Cargo.lock +22 -31
- package/src/rust/pkg/grapher_rs.d.ts +6 -0
- package/src/rust/pkg/grapher_rs.js +5 -0
- package/src/rust/pkg/grapher_rs_bg.js +305 -0
- package/src/rust/pkg/grapher_rs_bg.wasm +0 -0
- package/src/rust/pkg/grapher_rs_bg.wasm.d.ts +11 -0
- package/src/rust/pkg/index.js +397 -0
- package/src/state/calculate_tooltip_state.js +6 -6
- package/src/state/state_controller.js +20 -6
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -78,7 +78,7 @@ The `series` prop requires an array of objects, where each object represents a d
|
|
|
78
78
|
- **name**: Series name for display in legend
|
|
79
79
|
- **xLabel**: Label for x-axis
|
|
80
80
|
- **yLabel**: Label for y-axis
|
|
81
|
-
- **rendering**: Visual representation ('line', 'bar', or '
|
|
81
|
+
- **rendering**: Visual representation ('line', 'bar', 'area', or 'shadow', defaults to 'line'). The 'shadow' option creates an area chart with individual point-based (trapezoid) gradients extending downward.
|
|
82
82
|
- **ignoreDiscontinuities**: Whether to connect points across gaps (boolean)
|
|
83
83
|
- **dashed**: Whether to use dashed lines (boolean)
|
|
84
84
|
- **dashPattern**: Array defining dash pattern (array of numbers)
|
|
@@ -159,12 +159,52 @@ function GraphBody({ stateController, webgl, bodyHeight, boundsSelectionEnabled,
|
|
|
159
159
|
});
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
+
const getTouch = (event) => event.touches?.[0] || event.changedTouches?.[0];
|
|
163
|
+
|
|
164
|
+
const onGlobalTouchStart = (event) => {
|
|
165
|
+
if (!showTooltips) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const touch = getTouch(event);
|
|
169
|
+
if (!touch) return;
|
|
170
|
+
stateController.setTooltipMousePosition({
|
|
171
|
+
clientX: touch.clientX,
|
|
172
|
+
clientY: touch.clientY
|
|
173
|
+
});
|
|
174
|
+
if (event.cancelable) event.preventDefault();
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const onGlobalTouchMove = (event) => {
|
|
178
|
+
if (!showTooltips) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const touch = getTouch(event);
|
|
182
|
+
if (!touch) return;
|
|
183
|
+
stateController.setTooltipMousePosition({
|
|
184
|
+
clientX: touch.clientX,
|
|
185
|
+
clientY: touch.clientY
|
|
186
|
+
});
|
|
187
|
+
if (event.cancelable) event.preventDefault();
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const onGlobalTouchEnd = () => {
|
|
191
|
+
stateController.showOnlySavedTooltips();
|
|
192
|
+
};
|
|
193
|
+
|
|
162
194
|
window.addEventListener('scroll', onScroll, { passive: true });
|
|
163
195
|
window.addEventListener('mousemove', onGlobalMouseMove, { passive: true });
|
|
196
|
+
window.addEventListener('touchstart', onGlobalTouchStart, { passive: false });
|
|
197
|
+
window.addEventListener('touchmove', onGlobalTouchMove, { passive: false });
|
|
198
|
+
window.addEventListener('touchend', onGlobalTouchEnd, { passive: true });
|
|
199
|
+
window.addEventListener('touchcancel', onGlobalTouchEnd, { passive: true });
|
|
164
200
|
|
|
165
201
|
return () => {
|
|
166
202
|
window.removeEventListener('scroll', onScroll);
|
|
167
203
|
window.removeEventListener('mousemove', onGlobalMouseMove);
|
|
204
|
+
window.removeEventListener('touchstart', onGlobalTouchStart);
|
|
205
|
+
window.removeEventListener('touchmove', onGlobalTouchMove);
|
|
206
|
+
window.removeEventListener('touchend', onGlobalTouchEnd);
|
|
207
|
+
window.removeEventListener('touchcancel', onGlobalTouchEnd);
|
|
168
208
|
};
|
|
169
209
|
}, []);
|
|
170
210
|
|
|
@@ -319,4 +359,4 @@ GraphBody.propTypes = {
|
|
|
319
359
|
onPointClick: PropTypes.func,
|
|
320
360
|
clockStyle: PropTypes.oneOf(['12h', '24h']),
|
|
321
361
|
timeZone: PropTypes.string
|
|
322
|
-
};
|
|
362
|
+
};
|
|
@@ -32,6 +32,16 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
32
32
|
this.startRightDrag = this.startRightDrag.bind(this);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
getClientX(event) {
|
|
36
|
+
if (event && event.touches && event.touches[0]) {
|
|
37
|
+
return event.touches[0].clientX;
|
|
38
|
+
}
|
|
39
|
+
if (event && event.changedTouches && event.changedTouches[0]) {
|
|
40
|
+
return event.changedTouches[0].clientX;
|
|
41
|
+
}
|
|
42
|
+
return event.clientX;
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
componentDidMount() {
|
|
36
46
|
this._renderer = new GraphBodyRenderer({
|
|
37
47
|
stateController: this.props.stateController,
|
|
@@ -60,14 +70,16 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
componentDidUpdate(prevProps) {
|
|
63
|
-
if (prevProps.draggingY !== this.props.draggingY) {
|
|
73
|
+
if (prevProps.draggingY !== this.props.draggingY && this._renderer) {
|
|
64
74
|
this._renderer.resize();
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
componentWillUnmount() {
|
|
69
|
-
this._renderer
|
|
70
|
-
|
|
79
|
+
if (this._renderer) {
|
|
80
|
+
this._renderer.dispose();
|
|
81
|
+
this._renderer = null;
|
|
82
|
+
}
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
onMouseMove(event) {
|
|
@@ -75,11 +87,16 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
75
87
|
return;
|
|
76
88
|
}
|
|
77
89
|
|
|
90
|
+
// Prevent scrolling during touch-drag
|
|
91
|
+
if (event && event.touches && event.preventDefault) {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
let boundCalculator;
|
|
79
96
|
const leftX = this.el.getBoundingClientRect().left;
|
|
80
97
|
|
|
81
98
|
this.setState(({selectionBounds, globalBounds, elementWidth}) => {
|
|
82
|
-
const pixelX = event
|
|
99
|
+
const pixelX = this.getClientX(event) - leftX;
|
|
83
100
|
let percentage = pixelX/elementWidth;
|
|
84
101
|
|
|
85
102
|
percentage = Math.max(percentage, 0);
|
|
@@ -175,12 +192,19 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
175
192
|
addListeners() {
|
|
176
193
|
window.addEventListener('mousemove', this.onMouseMove);
|
|
177
194
|
window.addEventListener('mouseup', this.stopDragging);
|
|
195
|
+
window.addEventListener('touchmove', this.onMouseMove, { passive: false });
|
|
196
|
+
window.addEventListener('touchend', this.stopDragging);
|
|
197
|
+
window.addEventListener('touchcancel', this.stopDragging);
|
|
178
198
|
}
|
|
179
199
|
|
|
180
200
|
stopDragging() {
|
|
181
201
|
this._dragType = null;
|
|
202
|
+
this.forceUpdate();
|
|
182
203
|
window.removeEventListener('mousemove', this.onMouseMove);
|
|
183
204
|
window.removeEventListener('mouseup', this.stopDragging);
|
|
205
|
+
window.removeEventListener('touchmove', this.onMouseMove);
|
|
206
|
+
window.removeEventListener('touchend', this.stopDragging);
|
|
207
|
+
window.removeEventListener('touchcancel', this.stopDragging);
|
|
184
208
|
}
|
|
185
209
|
|
|
186
210
|
startScroll(event) {
|
|
@@ -189,7 +213,7 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
189
213
|
const {selectionBounds, globalBounds, elementWidth} = this.state;
|
|
190
214
|
const leftX = this.el.getBoundingClientRect().left;
|
|
191
215
|
|
|
192
|
-
const pixelStartX = event
|
|
216
|
+
const pixelStartX = this.getClientX(event) - leftX;
|
|
193
217
|
const pixelMinX = (selectionBounds.minX - globalBounds.minX)/(globalBounds.maxX - globalBounds.minX) * elementWidth || 0;
|
|
194
218
|
const pixelMaxX = (selectionBounds.maxX - globalBounds.minX)/(globalBounds.maxX - globalBounds.minX) * elementWidth || 0;
|
|
195
219
|
|
|
@@ -197,12 +221,12 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
197
221
|
this.addListeners();
|
|
198
222
|
}
|
|
199
223
|
|
|
200
|
-
startLeftDrag() {
|
|
224
|
+
startLeftDrag(event) {
|
|
201
225
|
this._dragType = 'left';
|
|
202
226
|
this.addListeners();
|
|
203
227
|
}
|
|
204
228
|
|
|
205
|
-
startRightDrag() {
|
|
229
|
+
startRightDrag(event) {
|
|
206
230
|
this._dragType = 'right';
|
|
207
231
|
this.addListeners();
|
|
208
232
|
}
|
|
@@ -222,6 +246,7 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
222
246
|
}
|
|
223
247
|
|
|
224
248
|
const barSize = 14;
|
|
249
|
+
const totalHeight = elementHeight + barSize;
|
|
225
250
|
let ticks;
|
|
226
251
|
|
|
227
252
|
if (selectionBounds.dates && this.props.markDates) {
|
|
@@ -246,10 +271,10 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
246
271
|
|
|
247
272
|
return (
|
|
248
273
|
<div className="range-selection-graph">
|
|
249
|
-
<div className="graph-body graph-body-secondary">
|
|
274
|
+
<div className="graph-body graph-body-secondary" style={{ touchAction: 'none' }}>
|
|
250
275
|
<canvas ref={(el) => this.el = el} />
|
|
251
276
|
|
|
252
|
-
<svg>
|
|
277
|
+
<svg style={{ height: totalHeight }}>
|
|
253
278
|
<g>
|
|
254
279
|
<rect
|
|
255
280
|
x={0}
|
|
@@ -266,6 +291,11 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
266
291
|
}
|
|
267
292
|
|
|
268
293
|
const classes = ['axis-item', `axis-item-${size}`, `axis-item-${position}`];
|
|
294
|
+
|
|
295
|
+
const isHighlighted = pixelValue >= pixelMinX && pixelValue <= pixelMaxX;
|
|
296
|
+
if (isHighlighted) {
|
|
297
|
+
classes.push('axis-item-highlighted');
|
|
298
|
+
}
|
|
269
299
|
|
|
270
300
|
return (
|
|
271
301
|
<g key={i} className={classes.join(' ')}>
|
|
@@ -286,6 +316,7 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
286
316
|
height={barSize}
|
|
287
317
|
className="selection-bar"
|
|
288
318
|
onMouseDown={this.startScroll}
|
|
319
|
+
onTouchStart={this.startScroll}
|
|
289
320
|
/>
|
|
290
321
|
|
|
291
322
|
<path
|
|
@@ -293,6 +324,7 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
293
324
|
className="selection-bar-rifles"
|
|
294
325
|
transform={`translate(${pixelMinX + (pixelMaxX - pixelMinX)/2},${elementHeight})`}
|
|
295
326
|
onMouseDown={this.startScroll}
|
|
327
|
+
onTouchStart={this.startScroll}
|
|
296
328
|
/>
|
|
297
329
|
</g>
|
|
298
330
|
|
|
@@ -301,37 +333,53 @@ export default class RangeGraph extends React.PureComponent {
|
|
|
301
333
|
x={pixelMinX}
|
|
302
334
|
y={0}
|
|
303
335
|
width={pixelMaxX - pixelMinX}
|
|
304
|
-
height={
|
|
305
|
-
className="target-selection"
|
|
306
|
-
onMouseDown={this.startScroll}
|
|
307
|
-
/>
|
|
308
|
-
|
|
309
|
-
<rect
|
|
310
|
-
x={pixelMinX}
|
|
311
|
-
y={0}
|
|
312
|
-
width={pixelMaxX - pixelMinX}
|
|
313
|
-
height={elementHeight + barSize}
|
|
336
|
+
height={totalHeight}
|
|
314
337
|
className="target-selection-outline"
|
|
315
338
|
/>
|
|
316
339
|
</g>
|
|
317
340
|
|
|
318
|
-
|
|
341
|
+
{/* Left handle */}
|
|
342
|
+
<g className={`selection-handle${(this._dragType === 'left' || this._dragType === 'scroll') ? ' selection-handle-dragging' : ''}`}>
|
|
343
|
+
<rect
|
|
344
|
+
x={pixelMinX - 15}
|
|
345
|
+
y={(elementHeight - 30)/2}
|
|
346
|
+
width={30}
|
|
347
|
+
height={30}
|
|
348
|
+
fill="transparent"
|
|
349
|
+
className="selection-bar-handle-hit"
|
|
350
|
+
onMouseDown={this.startLeftDrag}
|
|
351
|
+
onTouchStart={this.startLeftDrag}
|
|
352
|
+
/>
|
|
319
353
|
<path
|
|
320
354
|
d="M -4.5 0.5 L 3.5 0.5 L 3.5 15.5 L -4.5 15.5 L -4.5 0.5 M -1.5 4 L -1.5 12 M 0.5 4 L 0.5 12"
|
|
321
355
|
className="selection-bar-handle"
|
|
322
356
|
transform={`translate(${pixelMinX},${(elementHeight - 15)/2})`}
|
|
323
357
|
onMouseDown={this.startLeftDrag}
|
|
358
|
+
onTouchStart={this.startLeftDrag}
|
|
324
359
|
/>
|
|
325
360
|
</g>
|
|
326
361
|
|
|
327
|
-
|
|
362
|
+
{/* Right handle */}
|
|
363
|
+
<g className={`selection-handle${(this._dragType === 'right' || this._dragType === 'scroll') ? ' selection-handle-dragging' : ''}`}>
|
|
364
|
+
<rect
|
|
365
|
+
x={pixelMaxX - 15}
|
|
366
|
+
y={(elementHeight - 30)/2}
|
|
367
|
+
width={30}
|
|
368
|
+
height={30}
|
|
369
|
+
fill="transparent"
|
|
370
|
+
className="selection-bar-handle-hit"
|
|
371
|
+
onMouseDown={this.startRightDrag}
|
|
372
|
+
onTouchStart={this.startRightDrag}
|
|
373
|
+
/>
|
|
328
374
|
<path
|
|
329
375
|
d="M -4.5 0.5 L 3.5 0.5 L 3.5 15.5 L -4.5 15.5 L -4.5 0.5 M -1.5 4 L -1.5 12 M 0.5 4 L 0.5 12"
|
|
330
376
|
className="selection-bar-handle"
|
|
331
377
|
transform={`translate(${pixelMaxX},${(elementHeight - 15)/2})`}
|
|
332
378
|
onMouseDown={this.startRightDrag}
|
|
379
|
+
onTouchStart={this.startRightDrag}
|
|
333
380
|
/>
|
|
334
381
|
</g>
|
|
382
|
+
|
|
335
383
|
</svg>
|
|
336
384
|
|
|
337
385
|
{
|
|
@@ -365,4 +413,4 @@ RangeGraph.propTypes = {
|
|
|
365
413
|
markDates: PropTypes.bool,
|
|
366
414
|
timeZone: PropTypes.string,
|
|
367
415
|
verticalLines: CustomPropTypes.VerticalLines
|
|
368
|
-
};
|
|
416
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import {calculatePrecision, calculateTimePrecision, formatX} from '../helpers/format';
|
|
4
|
-
import placeGrid from '../helpers/place_grid';
|
|
4
|
+
import placeGrid, { placeTimeOnlyGrid, placeDateOnlyGrid } from '../helpers/place_grid';
|
|
5
5
|
import {useEnumMap, useHasXEnum, usePrimarySize, useSelection} from '../state/hooks';
|
|
6
6
|
import StateController from '../state/state_controller';
|
|
7
7
|
|
|
@@ -44,40 +44,153 @@ function XAxis({ showAxes, showGrid, stateController, bigLabels, xTickUnit, cloc
|
|
|
44
44
|
const minLabel = formatX(minX, {...formatOptions, dates, precision }).toString();
|
|
45
45
|
const maxLabel = formatX(maxX, {...formatOptions, dates, precision }).toString();
|
|
46
46
|
|
|
47
|
-
let expectedLabelWidth = Math.max(minLabel.length, maxLabel.length)
|
|
47
|
+
let expectedLabelWidth = Math.max(minLabel.length, maxLabel.length);
|
|
48
48
|
if (bigLabels) {
|
|
49
49
|
expectedLabelWidth *= 2;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const labelPadding = 30;
|
|
52
|
+
const labelPadding = 30;
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
let timeTicks = null;
|
|
55
|
+
let dateTicks = null;
|
|
56
|
+
let regularTicks = null;
|
|
57
|
+
|
|
58
|
+
if (dates) {
|
|
59
|
+
timeTicks = placeTimeOnlyGrid({
|
|
60
|
+
min: minX,
|
|
61
|
+
max: maxX,
|
|
62
|
+
totalSize: elementWidth,
|
|
63
|
+
precision,
|
|
64
|
+
expectedLabelSize: expectedLabelWidth,
|
|
65
|
+
labelPadding: labelPadding * 0.8,
|
|
66
|
+
formatter: formatXAxisLabel || formatX,
|
|
67
|
+
formatOptions
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
dateTicks = placeDateOnlyGrid({
|
|
71
|
+
min: minX,
|
|
72
|
+
max: maxX,
|
|
73
|
+
totalSize: elementWidth,
|
|
74
|
+
precision,
|
|
75
|
+
expectedLabelSize: expectedLabelWidth * 2,
|
|
76
|
+
labelPadding: labelPadding * 1.5,
|
|
77
|
+
formatter: formatXAxisLabel || formatX,
|
|
78
|
+
formatOptions
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
regularTicks = placeGrid({
|
|
82
|
+
min: minX,
|
|
83
|
+
max: maxX,
|
|
84
|
+
totalSize: elementWidth,
|
|
85
|
+
precision,
|
|
86
|
+
dates,
|
|
87
|
+
formatter: formatXAxisLabel || formatX,
|
|
88
|
+
expectedLabelSize: expectedLabelWidth,
|
|
89
|
+
labelPadding,
|
|
90
|
+
formatOptions
|
|
91
|
+
});
|
|
92
|
+
}
|
|
65
93
|
|
|
66
|
-
const xAxisHeight = 20;
|
|
94
|
+
const xAxisHeight = dates ? 30 : 20;
|
|
67
95
|
|
|
68
96
|
return (
|
|
69
|
-
<svg className=
|
|
97
|
+
<svg className={`axis x-axis${dates ? ' x-axis-dual' : ''}`} style={showAxes ? undefined : {marginBottom: -20}}>
|
|
70
98
|
{
|
|
71
99
|
showAxes &&
|
|
72
100
|
<path d={`M-1,0 H${elementWidth}`} className="axis-line" />
|
|
73
101
|
}
|
|
102
|
+
|
|
103
|
+
{/* Render time ticks in first row */}
|
|
74
104
|
{
|
|
75
|
-
|
|
76
|
-
|
|
105
|
+
dates && timeTicks && timeTicks.map(({ pixelValue, label, size, position, skipGrid }, i) => {
|
|
106
|
+
|
|
107
|
+
const singleTick = timeTicks.length === 1;
|
|
108
|
+
|
|
109
|
+
if (isNaN(pixelValue)) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const classes = ['axis-item', `axis-item-${size}`, `axis-item-${position}`];
|
|
114
|
+
if (bigLabels) {
|
|
115
|
+
classes.push('axis-item-big-labels');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<g key={`time-${i}`} className={classes.join(' ')}>
|
|
120
|
+
{
|
|
121
|
+
showAxes &&
|
|
122
|
+
<path d={`M${pixelValue},1 v12`} className="axis-tick" />
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
{
|
|
126
|
+
showGrid && !skipGrid &&
|
|
127
|
+
<path d={`M${pixelValue},0 v-${elementHeight}`} />
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
{
|
|
131
|
+
showAxes &&
|
|
132
|
+
<text
|
|
133
|
+
x={(position === 'last' && !singleTick) ? pixelValue - 3 : pixelValue + 3}
|
|
134
|
+
y={12}
|
|
135
|
+
textAnchor={(position === 'last' && !singleTick) ? 'end' : 'start'}
|
|
136
|
+
className='x-axis-text x-axis-time-text'
|
|
137
|
+
>
|
|
138
|
+
{label}
|
|
139
|
+
</text>
|
|
140
|
+
}
|
|
141
|
+
</g>
|
|
142
|
+
);
|
|
143
|
+
})
|
|
77
144
|
}
|
|
145
|
+
|
|
146
|
+
{/* Render date ticks in second row */}
|
|
147
|
+
{
|
|
148
|
+
dates && dateTicks && dateTicks.map(({ pixelValue, label, size, position, trueValue }, i) => {
|
|
149
|
+
|
|
150
|
+
if (isNaN(pixelValue)) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const classes = ['axis-item', `axis-item-${size}`, `axis-item-${position}`];
|
|
155
|
+
if (bigLabels) {
|
|
156
|
+
classes.push('axis-item-big-labels');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let timezoneLabel = undefined;
|
|
160
|
+
if (timeZone) {
|
|
161
|
+
if (i === 0) {
|
|
162
|
+
timezoneLabel = timeZone.toLowerCase() === 'utc' ? 'UTC' : timeZone;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
78
165
|
|
|
166
|
+
return (
|
|
167
|
+
<g key={`date-${i}`} className={classes.join(' ')}>
|
|
168
|
+
{
|
|
169
|
+
showAxes &&
|
|
170
|
+
<text
|
|
171
|
+
x={position === 'last' ? pixelValue - 3 : pixelValue + 3}
|
|
172
|
+
y={25}
|
|
173
|
+
textAnchor={position === 'last' ? 'end' : 'start'}
|
|
174
|
+
className='x-axis-text x-axis-date-text'
|
|
175
|
+
>
|
|
176
|
+
<tspan className='x-axis-date-label'>
|
|
177
|
+
{label}
|
|
178
|
+
</tspan>
|
|
179
|
+
{timezoneLabel && (
|
|
180
|
+
<tspan className='x-axis-timezone-label'>
|
|
181
|
+
{' '}({timezoneLabel})
|
|
182
|
+
</tspan>
|
|
183
|
+
)}
|
|
184
|
+
</text>
|
|
185
|
+
}
|
|
186
|
+
</g>
|
|
187
|
+
);
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
{/* Render regular ticks for non-date data */}
|
|
79
192
|
{
|
|
80
|
-
|
|
193
|
+
!dates && regularTicks && regularTicks.map(({ pixelValue, label, size, position, skipGrid }, i) => {
|
|
81
194
|
if (isNaN(pixelValue)) {
|
|
82
195
|
return null;
|
|
83
196
|
}
|
|
@@ -91,7 +204,7 @@ function XAxis({ showAxes, showGrid, stateController, bigLabels, xTickUnit, cloc
|
|
|
91
204
|
<g key={i} className={classes.join(' ')}>
|
|
92
205
|
{
|
|
93
206
|
showAxes &&
|
|
94
|
-
<path d={`M${pixelValue},1
|
|
207
|
+
<path d={`M${pixelValue},1 v12`} className="axis-tick" />
|
|
95
208
|
}
|
|
96
209
|
|
|
97
210
|
{
|
|
@@ -101,7 +214,12 @@ function XAxis({ showAxes, showGrid, stateController, bigLabels, xTickUnit, cloc
|
|
|
101
214
|
|
|
102
215
|
{
|
|
103
216
|
showAxes &&
|
|
104
|
-
<text
|
|
217
|
+
<text
|
|
218
|
+
x={position === 'last' ? pixelValue - 3 : pixelValue + 3}
|
|
219
|
+
y={xAxisHeight - 5}
|
|
220
|
+
textAnchor={position === 'last' ? 'end' : 'start'}
|
|
221
|
+
className='x-axis-text'
|
|
222
|
+
>
|
|
105
223
|
{label}
|
|
106
224
|
</text>
|
|
107
225
|
}
|
|
@@ -135,11 +135,6 @@ function YAxis({ stateController, showAxes, showGrid, showSeriesKey, axis, sideI
|
|
|
135
135
|
<path d={`M${side === 'left' ? Y_AXIS_WIDTH-1 : 1},3 V${elementHeight}`} className="axis-line" />
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
{
|
|
139
|
-
showAxes &&
|
|
140
|
-
<path d={`M${side === 'left' ? Y_AXIS_WIDTH-2 : 0},3 V${elementHeight + 1}`} className="axis-line-shadow" />
|
|
141
|
-
}
|
|
142
|
-
|
|
143
138
|
{
|
|
144
139
|
ticks.map(({ pixelValue, label, size, skipGrid }, i) => {
|
|
145
140
|
const edge = side === 'left' ? (sideIndex + 1) * Y_AXIS_WIDTH : -sideIndex*Y_AXIS_WIDTH;
|
package/src/grapher.jsx
CHANGED
|
@@ -156,11 +156,12 @@ function Grapher(props) {
|
|
|
156
156
|
const showingSidebar = useShowingSidebar(stateController);
|
|
157
157
|
|
|
158
158
|
const showAxisColors = typeof props.showAxisColors === 'boolean' ? props.showAxisColors : (theme !== 'export');
|
|
159
|
-
const showGrid = typeof props.showGrid === 'boolean' ? props.showGrid :
|
|
159
|
+
const showGrid = typeof props.showGrid === 'boolean' ? props.showGrid : true;
|
|
160
|
+
const showAxes = typeof props.showAxes === 'boolean' ? props.showAxes : false;
|
|
160
161
|
|
|
161
162
|
const commonYAxisProps = {
|
|
162
163
|
stateController,
|
|
163
|
-
showAxes
|
|
164
|
+
showAxes,
|
|
164
165
|
showGrid,
|
|
165
166
|
showSeriesKey: props.showSeriesKey,
|
|
166
167
|
bodyHeight: props.bodyHeight,
|
|
@@ -251,7 +252,7 @@ function Grapher(props) {
|
|
|
251
252
|
|
|
252
253
|
<XAxis
|
|
253
254
|
showGrid={showGrid}
|
|
254
|
-
showAxes={
|
|
255
|
+
showAxes={showAxes}
|
|
255
256
|
stateController={stateController}
|
|
256
257
|
bigLabels={bigLabels}
|
|
257
258
|
xTickUnit={props.xTickUnit}
|