inkplot 0.0.1-placeholder.0 → 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.md +45 -1
- package/dist/adapt.d.ts +10 -0
- package/dist/adapt.js +34 -0
- package/dist/annotation.d.ts +120 -0
- package/dist/annotation.js +267 -0
- package/dist/aria.d.ts +24 -0
- package/dist/aria.js +31 -0
- package/dist/attrs.d.ts +81 -0
- package/dist/attrs.js +84 -0
- package/dist/axis.d.ts +137 -0
- package/dist/axis.js +185 -0
- package/dist/bars.d.ts +80 -0
- package/dist/bars.js +255 -0
- package/dist/boxplot.d.ts +57 -0
- package/dist/boxplot.js +177 -0
- package/dist/boxzoom.d.ts +39 -0
- package/dist/boxzoom.js +138 -0
- package/dist/brush.d.ts +60 -0
- package/dist/brush.js +185 -0
- package/dist/bucket.d.ts +22 -0
- package/dist/bucket.js +62 -0
- package/dist/callout.d.ts +30 -0
- package/dist/callout.js +98 -0
- package/dist/chart.d.ts +126 -0
- package/dist/chart.js +257 -0
- package/dist/crosshair.d.ts +28 -0
- package/dist/crosshair.js +78 -0
- package/dist/cursor.d.ts +76 -0
- package/dist/cursor.js +344 -0
- package/dist/curve.d.ts +50 -0
- package/dist/curve.js +87 -0
- package/dist/curves.d.ts +104 -0
- package/dist/curves.js +375 -0
- package/dist/data.d.ts +209 -0
- package/dist/data.js +276 -0
- package/dist/decimation.d.ts +86 -0
- package/dist/decimation.js +410 -0
- package/dist/density.d.ts +55 -0
- package/dist/density.js +252 -0
- package/dist/dimension.d.ts +103 -0
- package/dist/dimension.js +205 -0
- package/dist/dom-platform.d.ts +53 -0
- package/dist/dom-platform.js +190 -0
- package/dist/element.d.ts +232 -0
- package/dist/element.js +414 -0
- package/dist/errors.d.ts +85 -0
- package/dist/errors.js +237 -0
- package/dist/events.d.ts +144 -0
- package/dist/events.js +19 -0
- package/dist/focus.d.ts +22 -0
- package/dist/focus.js +51 -0
- package/dist/furniture.d.ts +70 -0
- package/dist/furniture.js +166 -0
- package/dist/geometry.d.ts +40 -0
- package/dist/geometry.js +7 -0
- package/dist/heatmap.d.ts +57 -0
- package/dist/heatmap.js +207 -0
- package/dist/hit.d.ts +103 -0
- package/dist/hit.js +428 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +73 -0
- package/dist/input.d.ts +42 -0
- package/dist/input.js +166 -0
- package/dist/jsx-dev-runtime.d.ts +9 -0
- package/dist/jsx-dev-runtime.js +13 -0
- package/dist/jsx-runtime.d.ts +59 -0
- package/dist/jsx-runtime.js +81 -0
- package/dist/key.d.ts +118 -0
- package/dist/key.js +199 -0
- package/dist/legend.d.ts +36 -0
- package/dist/legend.js +220 -0
- package/dist/mapped.d.ts +80 -0
- package/dist/mapped.js +106 -0
- package/dist/marker.d.ts +143 -0
- package/dist/marker.js +213 -0
- package/dist/panzoom.d.ts +119 -0
- package/dist/panzoom.js +467 -0
- package/dist/plane.d.ts +173 -0
- package/dist/plane.js +370 -0
- package/dist/platform.d.ts +113 -0
- package/dist/platform.js +80 -0
- package/dist/png.d.ts +44 -0
- package/dist/png.js +71 -0
- package/dist/pointer.d.ts +54 -0
- package/dist/pointer.js +132 -0
- package/dist/quantile.d.ts +3 -0
- package/dist/quantile.js +11 -0
- package/dist/radial.d.ts +116 -0
- package/dist/radial.js +336 -0
- package/dist/react.d.ts +441 -0
- package/dist/react.js +252 -0
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +51 -0
- package/dist/renderer.d.ts +191 -0
- package/dist/renderer.js +164 -0
- package/dist/scale.d.ts +37 -0
- package/dist/scale.js +19 -0
- package/dist/scales.d.ts +69 -0
- package/dist/scales.js +134 -0
- package/dist/serialize.d.ts +77 -0
- package/dist/serialize.js +321 -0
- package/dist/series.d.ts +304 -0
- package/dist/series.js +513 -0
- package/dist/simple.d.ts +35 -0
- package/dist/simple.js +20 -0
- package/dist/sources.d.ts +116 -0
- package/dist/sources.js +237 -0
- package/dist/stack.d.ts +61 -0
- package/dist/stack.js +172 -0
- package/dist/stats.d.ts +38 -0
- package/dist/stats.js +159 -0
- package/dist/steps.d.ts +50 -0
- package/dist/steps.js +154 -0
- package/dist/stub.d.ts +3 -0
- package/dist/stub.js +5 -0
- package/dist/style-names.d.ts +1 -0
- package/dist/style-names.js +6 -0
- package/dist/summary.d.ts +44 -0
- package/dist/summary.js +58 -0
- package/dist/surface.d.ts +94 -0
- package/dist/surface.js +145 -0
- package/dist/table.d.ts +39 -0
- package/dist/table.js +37 -0
- package/dist/text.d.ts +23 -0
- package/dist/text.js +44 -0
- package/dist/theme.d.ts +174 -0
- package/dist/theme.js +73 -0
- package/dist/themes.d.ts +9 -0
- package/dist/themes.js +56 -0
- package/dist/time-intl.d.ts +194 -0
- package/dist/time-intl.js +144 -0
- package/dist/time-temporal.d.ts +236 -0
- package/dist/time-temporal.js +58 -0
- package/dist/time.d.ts +216 -0
- package/dist/time.js +154 -0
- package/dist/trend.d.ts +151 -0
- package/dist/trend.js +500 -0
- package/dist/web-components.d.ts +62 -0
- package/dist/web-components.js +264 -0
- package/package.json +48 -3
package/dist/marker.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { fractionsOf, lookKey, lookValues, resolveBindings, stepsFor } from './bucket.js';
|
|
2
|
+
import { EVENT_ATTACH } from './events.js';
|
|
3
|
+
import { circlePath, f2 } from './geometry.js';
|
|
4
|
+
import { SeriesRenderer } from './renderer.js';
|
|
5
|
+
/** Points further than this outside the plot are skipped when a bound size cannot say how far a marker reaches. */
|
|
6
|
+
const CULL_MARGIN = 16;
|
|
7
|
+
/** Writes a bound value onto the style by property name: bindings are keyed by string, the style is a typed record. */
|
|
8
|
+
const writeProperty = (v, property, value) => {
|
|
9
|
+
v[property] = value;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* The common work of all markers: cull what is off the plot, work out each point's look from its bindings, and group
|
|
13
|
+
* points that look alike into one path.
|
|
14
|
+
*
|
|
15
|
+
* Why grouping: a scatter of 100k points as 100k nodes is slow to build and to render. Instead each bound style is
|
|
16
|
+
* quantized into a few steps, a point's look is the combination of its steps (the `key`), and every point with the same
|
|
17
|
+
* key joins a single path. The number of nodes is then bounded by `maxNodes`, not by the data. Geometry (a bubble's
|
|
18
|
+
* radius) is not quantized: it goes straight into the path data, which costs the same however it varies.
|
|
19
|
+
*/
|
|
20
|
+
export class Marker extends SeriesRenderer {
|
|
21
|
+
/** Its fill (or its stroke, for a marker that is only a stroke), unless that is bound to data. */
|
|
22
|
+
get swatch() {
|
|
23
|
+
const a = this.attrs, series = this.requireParent(), bind = a.bind;
|
|
24
|
+
if (bind?.fill || bind?.stroke)
|
|
25
|
+
return null;
|
|
26
|
+
const look = this.styleFor([this.kind, 'marker', 'shape'], { stroke: a.stroke, strokeWidth: a.strokeWidth, fill: a.fill, opacity: a.opacity }, this.accent(series.accentColor));
|
|
27
|
+
return look.fill && look.fill !== 'none' ? look.fill : look.stroke && look.stroke !== 'none' ? look.stroke : null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* One marker in the middle of the box, as big as it is on the plot (no bigger than the box). What is bound to data takes
|
|
31
|
+
* the value at the middle of its dimension, since a sample stands for no point in particular.
|
|
32
|
+
*/
|
|
33
|
+
sample(s, parent, key, width, height) {
|
|
34
|
+
const a = this.attrs, series = this.requireParent();
|
|
35
|
+
const look = this.styleFor([this.kind, 'marker', 'shape'], { stroke: a.stroke, strokeWidth: a.strokeWidth, fill: a.fill, opacity: a.opacity }, this.accent(series.accentColor));
|
|
36
|
+
const v = { ...look, size: this.styleFor([this.kind, 'marker'], { size: a.size }).size };
|
|
37
|
+
for (const b of this.bindings)
|
|
38
|
+
writeProperty(v, b.property, b.axis.valueAt(0.5));
|
|
39
|
+
v.size = Math.min(v.size, width / 2, height / 2);
|
|
40
|
+
const n = s.node(key, 'path', { parent });
|
|
41
|
+
s.set(n, 'd', this.shape(width / 2, height / 2, v.size));
|
|
42
|
+
this.style(s, n, v);
|
|
43
|
+
}
|
|
44
|
+
/** Its size, or the largest a bound size gives, and a pixel for the stroke round it. */
|
|
45
|
+
get reach() {
|
|
46
|
+
const size = this.bindings.find((b) => !this.isGeometric(b.property) ? false : b.property === 'size');
|
|
47
|
+
const output = size?.axis?.output;
|
|
48
|
+
const r = output ? Math.max(output[0], output[1]) : this.styleFor([this.kind, 'marker'], { size: this.attrs.size }).size;
|
|
49
|
+
return r + 1;
|
|
50
|
+
}
|
|
51
|
+
// Which grouped nodes (by look key) and how many per-point nodes exist now, so the ones no longer used can be removed.
|
|
52
|
+
#keys = new Set();
|
|
53
|
+
#separate = 0;
|
|
54
|
+
/** The bound properties with their dimensions resolved. A property is stylistic unless the marker puts it in the path. */
|
|
55
|
+
get bindings() {
|
|
56
|
+
return resolveBindings(this.attrs.bind, this, (p) => this.isGeometric(p));
|
|
57
|
+
}
|
|
58
|
+
/** How many steps each stylistic binding is quantized to, so that the combinations stay within `maxNodes`. 0 when not grouping. */
|
|
59
|
+
get stepsPerBinding() {
|
|
60
|
+
return this.attrs.merge === false ? 0 : stepsFor(this.bindings, this.attrs.maxNodes ?? 1000);
|
|
61
|
+
}
|
|
62
|
+
onEvent(ev) {
|
|
63
|
+
if (ev.type === EVENT_ATTACH)
|
|
64
|
+
void this.stepsPerBinding; // throws now rather than at the first paint
|
|
65
|
+
super.onEvent(ev);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Three phases: (1) turn each bound channel into a column of 0..1 positions along its dimension; (2) walk the points,
|
|
69
|
+
* dropping gaps and those off the plot, building each marker's path data and choosing its node; (3) write the nodes
|
|
70
|
+
* and remove those that no longer have any marker.
|
|
71
|
+
*/
|
|
72
|
+
draw(points) {
|
|
73
|
+
const series = this.requireParent(), plane = series.plane;
|
|
74
|
+
const a = this.attrs, s = this.surface, counters = this.counters;
|
|
75
|
+
const t0 = performance.now();
|
|
76
|
+
const { data, count, stride } = points;
|
|
77
|
+
const w = plane.rect.width, h = plane.rect.height;
|
|
78
|
+
const merge = a.merge !== false;
|
|
79
|
+
const local = { stroke: a.stroke, strokeWidth: a.strokeWidth, fill: a.fill, opacity: a.opacity };
|
|
80
|
+
const look = this.styleFor([this.kind, 'marker', 'shape'], local, this.accent(series.accentColor));
|
|
81
|
+
const base = { ...look, size: this.styleFor([this.kind, 'marker'], { size: a.size }).size };
|
|
82
|
+
// Each binding becomes a column of positions along its dimension, 0..1.
|
|
83
|
+
const channels = series.channels;
|
|
84
|
+
const bindings = this.bindings;
|
|
85
|
+
const fractions = bindings.map((b) => fractionsOf(b, data, 2 + channels.indexOf(b.channel), stride, count));
|
|
86
|
+
const styled = bindings.flatMap((b, i) => (b.stylistic ? [{ b, f: fractions[i] }] : []));
|
|
87
|
+
const geometric = bindings.flatMap((b, i) => (b.stylistic ? [] : [{ b, f: fractions[i] }]))[0];
|
|
88
|
+
const steps = this.stepsPerBinding;
|
|
89
|
+
let bytes = 0;
|
|
90
|
+
const paths = new Map(); // look key → the path data of every marker with that look
|
|
91
|
+
let separate = 0;
|
|
92
|
+
const v = { ...base };
|
|
93
|
+
// The style handed to `style()` starts from the constants each time, then has the bound values written over it.
|
|
94
|
+
const reset = () => Object.assign(v, base);
|
|
95
|
+
for (let i = 0; i < count; i++) {
|
|
96
|
+
const x = data[i * stride], y = data[i * stride + 1];
|
|
97
|
+
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
98
|
+
continue;
|
|
99
|
+
const r = geometric ? geometric.b.axis.valueAt(geometric.f[i]) : base.size;
|
|
100
|
+
if (!(r >= 0))
|
|
101
|
+
continue;
|
|
102
|
+
const reach = geometric || !styled.length ? r : CULL_MARGIN + r;
|
|
103
|
+
if (x < -reach || x > w + reach || y < -reach || y > h + reach)
|
|
104
|
+
continue;
|
|
105
|
+
const d = this.shape(x, y, r);
|
|
106
|
+
bytes += d.length;
|
|
107
|
+
if (merge) {
|
|
108
|
+
const key = lookKey(styled, i, steps);
|
|
109
|
+
paths.set(key, (paths.get(key) ?? '') + d);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
reset();
|
|
113
|
+
for (const { b, f } of styled)
|
|
114
|
+
writeProperty(v, b.property, b.axis.valueAt(f[i]));
|
|
115
|
+
const node = s.node(`p${separate++}`, 'path');
|
|
116
|
+
s.set(node, 'd', d);
|
|
117
|
+
this.style(s, node, v);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
counters.stages.path += performance.now() - t0;
|
|
121
|
+
counters.pathBytes += bytes;
|
|
122
|
+
if (merge) {
|
|
123
|
+
for (const key of this.#keys)
|
|
124
|
+
if (!paths.has(key))
|
|
125
|
+
s.remove(`m${key}`);
|
|
126
|
+
for (let i = 0; i < this.#separate; i++)
|
|
127
|
+
s.remove(`p${i}`);
|
|
128
|
+
this.#separate = 0;
|
|
129
|
+
this.#keys = new Set(paths.keys());
|
|
130
|
+
for (const [key, d] of paths) {
|
|
131
|
+
reset();
|
|
132
|
+
lookValues(key, styled, steps, (property, value) => writeProperty(v, property, value));
|
|
133
|
+
const node = s.node(`m${key}`, 'path');
|
|
134
|
+
s.set(node, 'd', d);
|
|
135
|
+
this.style(s, node, v);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
for (const key of this.#keys)
|
|
140
|
+
s.remove(`m${key}`);
|
|
141
|
+
this.#keys.clear();
|
|
142
|
+
for (let i = separate; i < this.#separate; i++)
|
|
143
|
+
s.remove(`p${i}`);
|
|
144
|
+
this.#separate = separate;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* A dot is a stroke with no length, as wide as the dot is: the cheapest marker, and the one a dense scatter wants.
|
|
150
|
+
* Since its size is a stroke width, a bound `size` is one of the quantized styles, unlike on the other markers.
|
|
151
|
+
*/
|
|
152
|
+
export class DotMarker extends Marker {
|
|
153
|
+
kind = 'dotMarker';
|
|
154
|
+
accent(color) { return { stroke: color }; }
|
|
155
|
+
shape(x, y) { return `M${f2(x)} ${f2(y)}h0`; }
|
|
156
|
+
isGeometric() { return false; }
|
|
157
|
+
style(s, n, v) {
|
|
158
|
+
s.set(n, 'fill', 'none');
|
|
159
|
+
s.set(n, 'stroke', v.stroke);
|
|
160
|
+
s.set(n, 'stroke-width', f2(2 * v.size));
|
|
161
|
+
s.set(n, 'stroke-linecap', this.attrs.cap ?? 'round');
|
|
162
|
+
s.set(n, 'opacity', Math.round(v.opacity * 1000) / 1000);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Shapes made of strokes. The size is in the path data, so it varies per point at no cost. */
|
|
166
|
+
export class LineMarker extends Marker {
|
|
167
|
+
kind = 'lineMarker';
|
|
168
|
+
accent(color) { return { stroke: color }; }
|
|
169
|
+
isGeometric(property) { return property === 'size'; }
|
|
170
|
+
style(s, n, v) {
|
|
171
|
+
s.set(n, 'fill', 'none');
|
|
172
|
+
s.set(n, 'stroke', v.stroke);
|
|
173
|
+
s.set(n, 'stroke-width', f2(v.strokeWidth));
|
|
174
|
+
s.set(n, 'stroke-linecap', 'round');
|
|
175
|
+
s.set(n, 'opacity', Math.round(v.opacity * 1000) / 1000);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** ×: two diagonals, `size` from the centre to each end. */
|
|
179
|
+
export class CrossMarker extends LineMarker {
|
|
180
|
+
shape(x, y, r) {
|
|
181
|
+
return `M${f2(x - r)} ${f2(y - r)}l${f2(2 * r)} ${f2(2 * r)}M${f2(x - r)} ${f2(y + r)}l${f2(2 * r)} ${f2(-2 * r)}`;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** +: a horizontal and a vertical stroke. */
|
|
185
|
+
export class PlusMarker extends LineMarker {
|
|
186
|
+
shape(x, y, r) {
|
|
187
|
+
return `M${f2(x - r)} ${f2(y)}h${f2(2 * r)}M${f2(x)} ${f2(y - r)}v${f2(2 * r)}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Closed shapes, filled and stroked. The most flexible markers: stroke, stroke width, fill, opacity and size are all bindable. */
|
|
191
|
+
export class ShapeMarker extends Marker {
|
|
192
|
+
kind = 'shapeMarker';
|
|
193
|
+
accent(color) { return { fill: color }; }
|
|
194
|
+
isGeometric(property) { return property === 'size'; }
|
|
195
|
+
style(s, n, v) {
|
|
196
|
+
s.set(n, 'fill', v.fill);
|
|
197
|
+
s.set(n, 'stroke', v.stroke);
|
|
198
|
+
s.set(n, 'stroke-width', f2(v.strokeWidth));
|
|
199
|
+
s.set(n, 'opacity', Math.round(v.opacity * 1000) / 1000);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** A filled circle. A bubble series is this with `size` bound to a channel. */
|
|
203
|
+
export class CircleMarker extends ShapeMarker {
|
|
204
|
+
shape(x, y, r) {
|
|
205
|
+
return circlePath(x, y, r);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** A square, `size` from the centre to each side. */
|
|
209
|
+
export class SquareMarker extends ShapeMarker {
|
|
210
|
+
shape(x, y, r) {
|
|
211
|
+
return `M${f2(x - r)} ${f2(y - r)}h${f2(2 * r)}v${f2(2 * r)}h${f2(-2 * r)}z`;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Axis } from './axis.ts';
|
|
2
|
+
import { type BaseAttributes, ChartElement, type ElementRef } from './element.ts';
|
|
3
|
+
import { inputOf } from './input.ts';
|
|
4
|
+
import { type ChartEvent } from './events.ts';
|
|
5
|
+
import type { Plane } from './plane.ts';
|
|
6
|
+
/** What a key can do. */
|
|
7
|
+
export type PanZoomAction = 'left' | 'right' | 'up' | 'down' | 'pageLeft' | 'pageRight' | 'pageUp' | 'pageDown' | 'zoomIn' | 'zoomOut' | 'reset';
|
|
8
|
+
/** Keys, by `KeyboardEvent.key`, for each action. An action left out has the default keys; an empty list turns it off. */
|
|
9
|
+
export type PanZoomKeys = Partial<Record<PanZoomAction, readonly string[]>>;
|
|
10
|
+
/**
|
|
11
|
+
* The keys it answers to unless told otherwise. Arrows move the view a step; with Shift, or the Page keys, a page. `+` and `-`
|
|
12
|
+
* (with the `=` and `_` that share their keys) zoom about the middle, and `0` or Home puts the view back.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_PANZOOM_KEYS: Readonly<Record<PanZoomAction, readonly string[]>>;
|
|
15
|
+
export interface PanZoomAttributes extends BaseAttributes {
|
|
16
|
+
/** The axes it may move, as elements or ids. Default: all of the plane's that can be dragged along: not the rim of a polar or radar plane. */
|
|
17
|
+
axes?: readonly ElementRef<Axis>[];
|
|
18
|
+
/**
|
|
19
|
+
* Which way things may move. Default 'both'. Along one direction only, the other axes keep fitting what is in view.
|
|
20
|
+
* A radius axis counts as vertical.
|
|
21
|
+
*/
|
|
22
|
+
direction?: 'both' | 'horizontal' | 'vertical';
|
|
23
|
+
/** Drag with the primary button to pan. Default true. */
|
|
24
|
+
pan?: boolean;
|
|
25
|
+
/** Turn the wheel to zoom about the pointer. Default true. */
|
|
26
|
+
zoom?: boolean;
|
|
27
|
+
/** Keep the view inside the natural range of each axis, so there is no panning off the data or zooming out past it. Default true. */
|
|
28
|
+
limit?: boolean;
|
|
29
|
+
/** Zoom per wheel pixel, as a natural-log factor. Default 0.002, which is about 20% for one notch of a typical wheel. */
|
|
30
|
+
zoomSpeed?: number;
|
|
31
|
+
/**
|
|
32
|
+
* With the pointer (or both fingers) over an axis, a wheel turn, a pinch or a drag moves that axis alone. Default true. Off,
|
|
33
|
+
* the axes beside the plot take no input and a gesture always moves every axis, about the pointer.
|
|
34
|
+
*/
|
|
35
|
+
axisZoom?: boolean;
|
|
36
|
+
/** Zoom per pixel of a pinch on a trackpad, which browsers report as small wheel turns with Ctrl held. Default 0.02, ten times the wheel's step per pixel. */
|
|
37
|
+
pinchSpeed?: number;
|
|
38
|
+
/**
|
|
39
|
+
* What a touch does. 'two-finger' (the default): one finger scrolls the page as usual, and two pinch and pan the chart.
|
|
40
|
+
* 'always': one finger pans the chart too, and the page cannot be scrolled from it.
|
|
41
|
+
*/
|
|
42
|
+
touch?: 'two-finger' | 'always';
|
|
43
|
+
/**
|
|
44
|
+
* A finger that lets go while still moving carries the view on, slowing to a stop (a flick). Default true. Only a touch
|
|
45
|
+
* flicks, and only where one finger pans (`touch: 'always'`); a mouse drag stops where it is released.
|
|
46
|
+
*/
|
|
47
|
+
inertia?: boolean;
|
|
48
|
+
/** Two quick presses put every axis back to its natural range. Default true. */
|
|
49
|
+
resetOnDoubleClick?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* The keys, once the plot has keyboard focus. It is a tab stop, so Tab reaches it. Give the keys for the actions to change
|
|
52
|
+
* (`{ zoomIn: ['i'], reset: ['r'] }`; the others keep their defaults, see `DEFAULT_PANZOOM_KEYS`), or `false` for no keyboard
|
|
53
|
+
* control and no tab stop. Name the plot with `meta.title` (on this, or on its plane), which is what a screen reader says
|
|
54
|
+
* on arriving.
|
|
55
|
+
*/
|
|
56
|
+
keys?: PanZoomKeys | false;
|
|
57
|
+
/** How far an arrow moves the view, as a fraction of it. Default 0.1. A page is five times that, up to half. */
|
|
58
|
+
keyStep?: number;
|
|
59
|
+
/** The factor of one press of a zoom key. Default 1.25. */
|
|
60
|
+
keyZoom?: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Pan and zoom for the plane it sits in: a plane child that turns pointer input into view ranges on axes.
|
|
64
|
+
* Everything is worked out in the fractions of the scale, so it behaves the same on a linear axis, an inverted one,
|
|
65
|
+
* one on the far side, or one with a different scale: the value under the pointer stays under the pointer.
|
|
66
|
+
*
|
|
67
|
+
* It does not know what a plane looks like. Each axis' `Ruler` says how far along it a plot position is (`fractionAt`),
|
|
68
|
+
* so dragging along a spoke or a rectangle's edge is the same code; an axis whose ruler cannot say (the rim) is left alone.
|
|
69
|
+
*/
|
|
70
|
+
export declare class PanZoom extends ChartElement<Plane, [], PanZoomAttributes> {
|
|
71
|
+
#private;
|
|
72
|
+
static takesInput: typeof inputOf;
|
|
73
|
+
static attrTypes: {
|
|
74
|
+
keyStep: 2;
|
|
75
|
+
keyZoom: 2;
|
|
76
|
+
pinchSpeed: 2;
|
|
77
|
+
inertia: 3;
|
|
78
|
+
axisZoom: 3;
|
|
79
|
+
resetOnDoubleClick: 3;
|
|
80
|
+
zoomSpeed: 2;
|
|
81
|
+
keys: {
|
|
82
|
+
pageLeft: 0;
|
|
83
|
+
pageRight: 0;
|
|
84
|
+
pageUp: 0;
|
|
85
|
+
pageDown: 0;
|
|
86
|
+
zoomIn: 0;
|
|
87
|
+
zoomOut: 0;
|
|
88
|
+
};
|
|
89
|
+
id: 1;
|
|
90
|
+
meta: {
|
|
91
|
+
title: 1;
|
|
92
|
+
description: 1;
|
|
93
|
+
role: 1;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
/** Put every controlled axis back to the range its data asks for. */
|
|
97
|
+
reset(): void;
|
|
98
|
+
/** Marks it for `PointerListener`, which must come before it: it takes presses, so what it claims is not ours. */
|
|
99
|
+
readonly claimsPress = true;
|
|
100
|
+
onEvent(ev: ChartEvent): void;
|
|
101
|
+
/** The axes a gesture at an axis' strip moves: that axis alone (`axisZoom`), or everything it controls. */
|
|
102
|
+
private targets;
|
|
103
|
+
/** The keys in force: the defaults with the ones asked for laid over them, or none. */
|
|
104
|
+
get keyMap(): PanZoomKeys | null;
|
|
105
|
+
/** The axes this will move, as of now: the chosen ones (or all the plane's) that can be followed along and fit `direction`. */
|
|
106
|
+
private controlled;
|
|
107
|
+
/**
|
|
108
|
+
* What the limit is measured against: the range all of the data on this axis asks for, not the part in view.
|
|
109
|
+
* (If it were the part in view, zooming one axis would move the limit of the other under your hand.)
|
|
110
|
+
*/
|
|
111
|
+
private limitFor;
|
|
112
|
+
/** Applies the change and sets the axis' view range; a view that covers the natural range is recorded as no view at all. */
|
|
113
|
+
private apply;
|
|
114
|
+
/**
|
|
115
|
+
* The new range, 'natural' if the change ends up covering all of it, or null to leave things as they are.
|
|
116
|
+
* A display fraction `d` along the axis is `u` in the scale's own fractions, flipped when the axis is inverted.
|
|
117
|
+
*/
|
|
118
|
+
private viewFor;
|
|
119
|
+
}
|