svelteplot 0.0.1-alpha.1 → 0.0.1-alpha.3
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/Plot.svelte +171 -0
- package/dist/Plot.svelte.d.ts +15 -0
- package/dist/classes/Channel.svelte.js +72 -0
- package/dist/classes/Mark.svelte.js +17 -0
- package/dist/classes/Plot.svelte.js +99 -0
- package/dist/contants.d.ts +3 -0
- package/dist/contants.js +40 -0
- package/dist/helpers/GroupMultiple.svelte +8 -0
- package/dist/helpers/GroupMultiple.svelte.d.ts +19 -0
- package/dist/helpers/autoTimeFormat.d.ts +2 -0
- package/dist/helpers/autoTimeFormat.js +10 -0
- package/dist/helpers/colors.d.ts +13 -0
- package/dist/helpers/colors.js +200 -0
- package/dist/helpers/createScale.d.ts +4 -0
- package/dist/helpers/createScale.js +47 -0
- package/dist/helpers/getBaseStyles.d.ts +2 -0
- package/dist/helpers/getBaseStyles.js +18 -0
- package/dist/helpers/getLogTicks.d.ts +1 -0
- package/dist/helpers/getLogTicks.js +57 -0
- package/dist/helpers/isDataRecord.d.ts +2 -0
- package/dist/helpers/isDataRecord.js +13 -0
- package/dist/helpers/mergeDeep.d.ts +5 -0
- package/dist/helpers/mergeDeep.js +26 -0
- package/dist/helpers/removeIdenticalLines.d.ts +1 -0
- package/dist/helpers/removeIdenticalLines.js +16 -0
- package/dist/helpers/resolveChannel.d.ts +2 -0
- package/dist/helpers/resolveChannel.js +28 -0
- package/dist/helpers/symbols.d.ts +5 -0
- package/dist/helpers/symbols.js +51 -0
- package/dist/helpers/typeChecks.d.ts +7 -0
- package/dist/helpers/typeChecks.js +21 -0
- package/dist/helpers/wrapArray.d.ts +2 -0
- package/dist/helpers/wrapArray.js +4 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/marks/AxisX.svelte +101 -0
- package/dist/marks/AxisX.svelte.d.ts +17 -0
- package/dist/marks/AxisY.svelte +69 -0
- package/dist/marks/AxisY.svelte.d.ts +15 -0
- package/dist/marks/BaseMark.svelte +22 -0
- package/dist/marks/BaseMark.svelte.d.ts +19 -0
- package/dist/marks/ColorLegend.svelte +52 -0
- package/dist/marks/ColorLegend.svelte.d.ts +14 -0
- package/dist/marks/Dot.svelte +83 -0
- package/dist/marks/Dot.svelte.d.ts +15 -0
- package/dist/marks/DotX.svelte +5 -0
- package/dist/marks/DotX.svelte.d.ts +17 -0
- package/dist/marks/DotY.svelte +5 -0
- package/dist/marks/DotY.svelte.d.ts +17 -0
- package/dist/marks/Frame.svelte +37 -0
- package/dist/marks/Frame.svelte.d.ts +15 -0
- package/dist/marks/GridX.svelte +42 -0
- package/dist/marks/GridX.svelte.d.ts +19 -0
- package/dist/marks/GridY.svelte +31 -0
- package/dist/marks/GridY.svelte.d.ts +15 -0
- package/dist/marks/Line.svelte +49 -0
- package/dist/marks/Line.svelte.d.ts +15 -0
- package/dist/marks/LineX.svelte +10 -0
- package/dist/marks/LineX.svelte.d.ts +17 -0
- package/dist/marks/LineY.svelte +10 -0
- package/dist/marks/LineY.svelte.d.ts +17 -0
- package/dist/marks/RuleX.svelte +30 -0
- package/dist/marks/RuleX.svelte.d.ts +15 -0
- package/dist/marks/RuleY.svelte +31 -0
- package/dist/marks/RuleY.svelte.d.ts +15 -0
- package/dist/marks/SymbolLegend.svelte +50 -0
- package/dist/marks/SymbolLegend.svelte.d.ts +14 -0
- package/dist/types.d.ts +188 -0
- package/dist/types.js +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const Scales: Record<string, (domain: number[], range: [number, number]) => (val: any) => any>;
|
|
2
|
+
export declare function createScale(type: keyof typeof Scales, domain: any, range: any, options?: {}): (val: any) => any;
|
|
3
|
+
export declare function createColorScale(type: any, domain: string[] | [number, number] | [Date, Date] | [boolean | boolean], scheme: any): ((d: any) => any) | (unknown[] & string[] & import("d3-scale").ScaleOrdinal<string, unknown, never>);
|
|
4
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { scaleBand, scaleLinear, scaleTime, scaleSqrt, scaleLog, scaleOrdinal } from 'd3-scale';
|
|
2
|
+
import { getLogTicks } from './getLogTicks';
|
|
3
|
+
import { categoricalSchemes, isCategoricalScheme, isOrdinalScheme, ordinalScheme } from './colors';
|
|
4
|
+
import { isColorOrNull } from './typeChecks';
|
|
5
|
+
const Scales = {
|
|
6
|
+
band: scaleBand,
|
|
7
|
+
linear: scaleLinear,
|
|
8
|
+
time: scaleTime,
|
|
9
|
+
sqrt: scaleSqrt,
|
|
10
|
+
log: scaleLog,
|
|
11
|
+
ordinal: scaleOrdinal
|
|
12
|
+
};
|
|
13
|
+
export function createScale(type, domain, range, options = {}) {
|
|
14
|
+
const scale = Scales[type](domain, range);
|
|
15
|
+
// allow setting arbiraty scale options
|
|
16
|
+
for (const [key, val] of Object.entries(options)) {
|
|
17
|
+
if (typeof scale[key] === 'function')
|
|
18
|
+
scale[key](val);
|
|
19
|
+
else
|
|
20
|
+
console.warn('unknown scale setter ' + key);
|
|
21
|
+
}
|
|
22
|
+
if (type === 'log') {
|
|
23
|
+
// overwrite scaleLog's internal ticks() method
|
|
24
|
+
scale.ticks = (count) => getLogTicks(domain, count);
|
|
25
|
+
// console.log({domain})
|
|
26
|
+
// console.log(getLogTicks(domain, 5))
|
|
27
|
+
}
|
|
28
|
+
return scale;
|
|
29
|
+
}
|
|
30
|
+
const identity = (d) => d;
|
|
31
|
+
export function createColorScale(type, domain, scheme) {
|
|
32
|
+
if (type === 'band') {
|
|
33
|
+
if (domain.every(isColorOrNull)) {
|
|
34
|
+
console.log('domain is colors', domain);
|
|
35
|
+
return identity;
|
|
36
|
+
}
|
|
37
|
+
const colorRange = !scheme
|
|
38
|
+
? categoricalSchemes.get('tableau10')
|
|
39
|
+
: Array.isArray(scheme)
|
|
40
|
+
? scheme
|
|
41
|
+
: isCategoricalScheme(scheme)
|
|
42
|
+
? categoricalSchemes.get(scheme)
|
|
43
|
+
: ordinalScheme(scheme)(domain.length);
|
|
44
|
+
return scaleOrdinal().domain(domain).range(colorRange);
|
|
45
|
+
}
|
|
46
|
+
return (d) => d;
|
|
47
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MARK_PROP_CHANNEL } from '../contants';
|
|
2
|
+
import resolveChannel from './resolveChannel';
|
|
3
|
+
const styleProps = {
|
|
4
|
+
fill: 'fill',
|
|
5
|
+
stroke: 'stroke',
|
|
6
|
+
strokeWidth: 'stroke-width',
|
|
7
|
+
strokeDasharray: 'stroke-dasharray',
|
|
8
|
+
fillOpacity: 'fill-opacity',
|
|
9
|
+
strokeOpacity: 'stroke-opacity',
|
|
10
|
+
fontSize: 'font-size',
|
|
11
|
+
opacity: 'opacity'
|
|
12
|
+
};
|
|
13
|
+
export default function (datum, props) {
|
|
14
|
+
return Object.entries(styleProps)
|
|
15
|
+
.filter(([key, cssKey]) => cssKey && props[key] != null)
|
|
16
|
+
.map(([key, cssKey]) => `${cssKey}: ${resolveChannel(MARK_PROP_CHANNEL[key], datum, props[key])}`)
|
|
17
|
+
.join(';');
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getLogTicks(domain: [number, number], count?: number): number[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ticks as ticksArray } from 'd3-array';
|
|
2
|
+
export function getLogTicks(domain, count = 6) {
|
|
3
|
+
const inverted = domain[0] < 0 && domain[1] < 0;
|
|
4
|
+
if (inverted)
|
|
5
|
+
domain = [domain[0] * -1, domain[1] * -1];
|
|
6
|
+
const reversed = domain[1] < domain[0];
|
|
7
|
+
if (reversed)
|
|
8
|
+
domain = domain.slice(0).reverse();
|
|
9
|
+
if (domain[0] < 0 || domain[1] < 0)
|
|
10
|
+
return [];
|
|
11
|
+
if (domain[0] === 0)
|
|
12
|
+
return ticksArray(domain[0], domain[1], count - 2);
|
|
13
|
+
let mult = Math.pow(10, Math.floor(Math.log10(Math.abs(domain[1] - domain[0]))) - 1);
|
|
14
|
+
count += 2;
|
|
15
|
+
let candidates = getTickCandidates(domain, mult);
|
|
16
|
+
if (candidates[0].num > count) {
|
|
17
|
+
// too many ticks
|
|
18
|
+
while (candidates[0].num > count) {
|
|
19
|
+
mult *= 10;
|
|
20
|
+
candidates = getTickCandidates(domain, mult);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (candidates[candidates.length - 1].num < count) {
|
|
24
|
+
// not enough ticks, let's fallback to linear ticks
|
|
25
|
+
const ticksList = ticksArray(domain[0], domain[1], count - 2);
|
|
26
|
+
if (reversed)
|
|
27
|
+
ticksList.reverse();
|
|
28
|
+
return ticksList;
|
|
29
|
+
}
|
|
30
|
+
count -= 2;
|
|
31
|
+
const ticksList = candidates
|
|
32
|
+
.map((d) => ({
|
|
33
|
+
...d,
|
|
34
|
+
ticks: d.ticks.filter((t) => t >= domain[0] && t <= domain[1])
|
|
35
|
+
}))
|
|
36
|
+
.map((d) => ({ ...d, diff: Math.abs(d.ticks.length - count) }))
|
|
37
|
+
.sort((a, b) => a.diff - b.diff)[0].ticks;
|
|
38
|
+
if (reversed)
|
|
39
|
+
ticksList.reverse();
|
|
40
|
+
if (inverted)
|
|
41
|
+
return ticksList.map((t) => t * -1);
|
|
42
|
+
return ticksList;
|
|
43
|
+
}
|
|
44
|
+
const logSeries = [[10], [5, 4, 5], [3, 10 / 3], [2, 2.5, 2], [1.5, 2, 5 / 3, 2]];
|
|
45
|
+
function getTickCandidates(domain, mult = 1) {
|
|
46
|
+
return logSeries.map((factors) => {
|
|
47
|
+
let i = Math.pow(10, Math.floor(Math.log10(domain[0])));
|
|
48
|
+
let f = 0;
|
|
49
|
+
const r = [i];
|
|
50
|
+
while (i < domain[1] && r.length < 50) {
|
|
51
|
+
i *= factors[f] * mult;
|
|
52
|
+
r.push(i);
|
|
53
|
+
f = (f + 1) % factors.length;
|
|
54
|
+
}
|
|
55
|
+
return { ticks: r, num: r.length };
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default function (value) {
|
|
2
|
+
if (typeof value !== 'object' || value === null)
|
|
3
|
+
return false;
|
|
4
|
+
if (Object.prototype.toString.call(value) !== '[object Object]')
|
|
5
|
+
return false;
|
|
6
|
+
const proto = Object.getPrototypeOf(value);
|
|
7
|
+
if (proto === null)
|
|
8
|
+
return true;
|
|
9
|
+
const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') && proto.constructor;
|
|
10
|
+
return (typeof Ctor === 'function' &&
|
|
11
|
+
Ctor instanceof Ctor &&
|
|
12
|
+
Function.prototype.call(Ctor) === Function.prototype.call(value));
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2
|
+
function isObject(item) {
|
|
3
|
+
return item && typeof item === 'object' && !Array.isArray(item);
|
|
4
|
+
}
|
|
5
|
+
export default function mergeDeep(target, ...sources) {
|
|
6
|
+
if (!sources.length)
|
|
7
|
+
return target;
|
|
8
|
+
const source = sources.shift();
|
|
9
|
+
if (isObject(target) && isObject(source)) {
|
|
10
|
+
for (const key in source) {
|
|
11
|
+
if (isObject(source[key])) {
|
|
12
|
+
if (!target[key]) {
|
|
13
|
+
Object.assign(target, { [key]: {} });
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
target[key] = Object.assign({}, target[key]);
|
|
17
|
+
}
|
|
18
|
+
mergeDeep(target[key], source[key]);
|
|
19
|
+
}
|
|
20
|
+
else if (source[key] !== null) {
|
|
21
|
+
Object.assign(target, { [key]: source[key] });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return mergeDeep(target, ...sources);
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function removeIdenticalLines(input: string[][]): string[][];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default function removeIdenticalLines(input) {
|
|
2
|
+
const uniqueLines = [];
|
|
3
|
+
if (!input.length)
|
|
4
|
+
return input;
|
|
5
|
+
for (let c = 0; c < input.length; c++) {
|
|
6
|
+
uniqueLines.push([]);
|
|
7
|
+
}
|
|
8
|
+
for (let l = 0; l < input[0].length; l++) {
|
|
9
|
+
const isIdentical = input.every((value) => input[0][l] === value[l]);
|
|
10
|
+
for (let c = 0; c < input.length; c++) {
|
|
11
|
+
if (!isIdentical)
|
|
12
|
+
uniqueLines[c].push(input[c][l]);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return uniqueLines;
|
|
16
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import isDataRecord from './isDataRecord';
|
|
2
|
+
export default function (channel, datum, accessor = null) {
|
|
3
|
+
if ((channel === 'x' || channel === 'y') && Array.isArray(datum) && accessor === null) {
|
|
4
|
+
// special case for [[x0,y0], [x1,y1], ...] format
|
|
5
|
+
return datum[channel === 'x' ? 0 : 1];
|
|
6
|
+
}
|
|
7
|
+
else if (isDataRecord(datum)) {
|
|
8
|
+
// use accessor function
|
|
9
|
+
if (typeof accessor === 'function')
|
|
10
|
+
return accessor(datum.___orig___ ? datum.___orig___ : datum);
|
|
11
|
+
// use accessor string
|
|
12
|
+
if (typeof accessor === 'string' && datum[accessor] !== undefined)
|
|
13
|
+
return datum[accessor];
|
|
14
|
+
// fallback to channel name as accessor
|
|
15
|
+
if (accessor === null && datum[channel] !== undefined)
|
|
16
|
+
return datum[channel];
|
|
17
|
+
// interpret accessor as constant
|
|
18
|
+
return accessor;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// return single value or accessor
|
|
22
|
+
return typeof accessor === 'function'
|
|
23
|
+
? accessor(datum)
|
|
24
|
+
: accessor !== null
|
|
25
|
+
? accessor
|
|
26
|
+
: datum;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type SymbolType } from 'd3-shape';
|
|
2
|
+
export declare const sqrt3: number;
|
|
3
|
+
export declare const sqrt4_3: number;
|
|
4
|
+
export declare function isSymbol(value: string | SymbolType): boolean;
|
|
5
|
+
export declare function maybeSymbol(symbol: SymbolType | string): SymbolType;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { symbolAsterisk, symbolDiamond2, symbolPlus, symbolSquare2, symbolTriangle2, symbolX as symbolTimes, symbolCircle, symbolCross, symbolDiamond, symbolSquare, symbolStar, symbolTriangle, symbolWye } from 'd3-shape';
|
|
2
|
+
export const sqrt3 = Math.sqrt(3);
|
|
3
|
+
export const sqrt4_3 = 2 / sqrt3;
|
|
4
|
+
const symbolHexagon = {
|
|
5
|
+
draw(context, size) {
|
|
6
|
+
const rx = Math.sqrt(size / Math.PI), ry = rx * sqrt4_3, hy = ry / 2;
|
|
7
|
+
context.moveTo(0, ry);
|
|
8
|
+
context.lineTo(rx, hy);
|
|
9
|
+
context.lineTo(rx, -hy);
|
|
10
|
+
context.lineTo(0, -ry);
|
|
11
|
+
context.lineTo(-rx, -hy);
|
|
12
|
+
context.lineTo(-rx, hy);
|
|
13
|
+
context.closePath();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const symbols = new Map([
|
|
17
|
+
['asterisk', symbolAsterisk],
|
|
18
|
+
['circle', symbolCircle],
|
|
19
|
+
['cross', symbolCross],
|
|
20
|
+
['diamond', symbolDiamond],
|
|
21
|
+
['diamond2', symbolDiamond2],
|
|
22
|
+
['hexagon', symbolHexagon],
|
|
23
|
+
['plus', symbolPlus],
|
|
24
|
+
['square', symbolSquare],
|
|
25
|
+
['square2', symbolSquare2],
|
|
26
|
+
['star', symbolStar],
|
|
27
|
+
['times', symbolTimes],
|
|
28
|
+
['triangle', symbolTriangle],
|
|
29
|
+
['triangle2', symbolTriangle2],
|
|
30
|
+
['wye', symbolWye]
|
|
31
|
+
]);
|
|
32
|
+
function isSymbolObject(value) {
|
|
33
|
+
if (typeof value === 'string')
|
|
34
|
+
return false;
|
|
35
|
+
return value && typeof value.draw === 'function';
|
|
36
|
+
}
|
|
37
|
+
export function isSymbol(value) {
|
|
38
|
+
if (isSymbolObject(value))
|
|
39
|
+
return true;
|
|
40
|
+
if (typeof value !== 'string')
|
|
41
|
+
return false;
|
|
42
|
+
return symbols.has(value.toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
export function maybeSymbol(symbol) {
|
|
45
|
+
if (symbol == null || isSymbolObject(symbol))
|
|
46
|
+
return symbol;
|
|
47
|
+
const value = symbols.get(`${symbol}`.toLowerCase());
|
|
48
|
+
if (value)
|
|
49
|
+
return value;
|
|
50
|
+
throw new Error(`invalid symbol: ${symbol}`);
|
|
51
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RawValue } from '../types';
|
|
2
|
+
export declare function isBooleanOrNull(v: RawValue): boolean;
|
|
3
|
+
export declare function isDateOrNull(v: RawValue): boolean;
|
|
4
|
+
export declare function isNumberOrNull(v: RawValue): boolean;
|
|
5
|
+
export declare function isStringOrNull(v: RawValue): boolean;
|
|
6
|
+
export declare function isColorOrNull(v: RawValue): boolean;
|
|
7
|
+
export declare function isOpacityOrNull(v: RawValue): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import chroma from 'chroma-js';
|
|
2
|
+
import { isDate, isFinite } from 'underscore';
|
|
3
|
+
export function isBooleanOrNull(v) {
|
|
4
|
+
return v == null || typeof v === 'boolean';
|
|
5
|
+
}
|
|
6
|
+
export function isDateOrNull(v) {
|
|
7
|
+
return v == null || isDate(v);
|
|
8
|
+
}
|
|
9
|
+
export function isNumberOrNull(v) {
|
|
10
|
+
return v == null || isFinite(v);
|
|
11
|
+
}
|
|
12
|
+
export function isStringOrNull(v) {
|
|
13
|
+
return v == null || typeof v === 'string';
|
|
14
|
+
}
|
|
15
|
+
export function isColorOrNull(v) {
|
|
16
|
+
// todo: maybe not use chroma.js here to save kb
|
|
17
|
+
return v == null || (typeof v === 'string' && chroma.valid(v));
|
|
18
|
+
}
|
|
19
|
+
export function isOpacityOrNull(v) {
|
|
20
|
+
return v == null || (typeof v === 'number' && isFinite(v) && v >= 0 && v <= 1);
|
|
21
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { default as Dot } from './marks/Dot.svelte';
|
|
2
|
+
export { default as DotX } from './marks/DotX.svelte';
|
|
3
|
+
export { default as DotY } from './marks/DotY.svelte';
|
|
4
|
+
export { default as Plot } from './Plot.svelte';
|
|
5
|
+
export { default as Frame } from './marks/Frame.svelte';
|
|
6
|
+
export { default as GridX } from './marks/GridX.svelte';
|
|
7
|
+
export { default as GridY } from './marks/GridY.svelte';
|
|
8
|
+
export { default as Line } from './marks/Line.svelte';
|
|
9
|
+
export { default as LineX } from './marks/LineX.svelte';
|
|
10
|
+
export { default as LineY } from './marks/LineY.svelte';
|
|
11
|
+
export { default as RuleX } from './marks/RuleX.svelte';
|
|
12
|
+
export { default as RuleY } from './marks/RuleY.svelte';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Reexport your entry components here
|
|
2
|
+
export { default as Dot } from './marks/Dot.svelte';
|
|
3
|
+
export { default as DotX } from './marks/DotX.svelte';
|
|
4
|
+
export { default as DotY } from './marks/DotY.svelte';
|
|
5
|
+
export { default as Plot } from './Plot.svelte';
|
|
6
|
+
export { default as Frame } from './marks/Frame.svelte';
|
|
7
|
+
export { default as GridX } from './marks/GridX.svelte';
|
|
8
|
+
export { default as GridY } from './marks/GridY.svelte';
|
|
9
|
+
export { default as Line } from './marks/Line.svelte';
|
|
10
|
+
export { default as LineX } from './marks/LineX.svelte';
|
|
11
|
+
export { default as LineY } from './marks/LineY.svelte';
|
|
12
|
+
export { default as RuleX } from './marks/RuleX.svelte';
|
|
13
|
+
export { default as RuleY } from './marks/RuleY.svelte';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script>import { getContext } from "svelte";
|
|
2
|
+
import BaseMark from "./BaseMark.svelte";
|
|
3
|
+
import resolveChannel from "../helpers/resolveChannel";
|
|
4
|
+
import getBaseStyles from "../helpers/getBaseStyles";
|
|
5
|
+
import removeIdenticalLines from "../helpers/removeIdenticalLines";
|
|
6
|
+
import autoTimeFormat from "../helpers/autoTimeFormat";
|
|
7
|
+
import dayjs from "dayjs";
|
|
8
|
+
import { get } from "underscore";
|
|
9
|
+
const BaseMark_AxisX = BaseMark;
|
|
10
|
+
const plot = getContext("svelteplot");
|
|
11
|
+
let {
|
|
12
|
+
ticks = [],
|
|
13
|
+
anchor = "bottom",
|
|
14
|
+
tickSize = 6,
|
|
15
|
+
tickPadding = 3,
|
|
16
|
+
tickFormat = null,
|
|
17
|
+
automatic = false,
|
|
18
|
+
title = null,
|
|
19
|
+
tickFontSize = null,
|
|
20
|
+
fill = null,
|
|
21
|
+
...styleProps
|
|
22
|
+
} = $props();
|
|
23
|
+
let autoTickCount = $derived(plot.plotWidth / get(plot, "options.x.tickSpacing", 80));
|
|
24
|
+
let autoTicks = $derived(
|
|
25
|
+
ticks.length > 0 ? ticks : get(plot, "options.x.ticks", plot.xScale.ticks(autoTickCount))
|
|
26
|
+
);
|
|
27
|
+
let useTickFormat = $derived(
|
|
28
|
+
typeof tickFormat === "function" ? tickFormat : plot.x.scaleType === "time" ? typeof tickFormat === "string" ? (d) => dayjs(d).format(tickFormat).split("\n") : autoTimeFormat(plot.x, plot.plotWidth) : (d) => String(d)
|
|
29
|
+
);
|
|
30
|
+
let tickTexts = $derived(
|
|
31
|
+
removeIdenticalLines(
|
|
32
|
+
autoTicks.map(useTickFormat).map((tick) => Array.isArray(tick) ? tick : [tick])
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
let optionsLabel = $derived(plot.options?.x?.label);
|
|
36
|
+
let useTitle = $derived(
|
|
37
|
+
title || (optionsLabel === null ? null : optionsLabel === void 0 ? plot.x.autoTitle : optionsLabel)
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<BaseMark_AxisX type="axis-x" data={ticks} channels={['x']} {automatic}>
|
|
42
|
+
<g class="axis-x">
|
|
43
|
+
{#if useTitle}
|
|
44
|
+
<text
|
|
45
|
+
x={plot.plotWidth + plot.margins.left}
|
|
46
|
+
y={plot.height - 10}
|
|
47
|
+
class="axis-title"
|
|
48
|
+
dominant-baseline="hanging">{useTitle} →</text
|
|
49
|
+
>
|
|
50
|
+
{/if}
|
|
51
|
+
{#each autoTicks as tick, t}
|
|
52
|
+
{@const textLines = tickTexts[t]}
|
|
53
|
+
{@const prevTextLines = t && tickTexts[t - 1]}
|
|
54
|
+
<g
|
|
55
|
+
class="x-tick"
|
|
56
|
+
transform="translate({plot.xScale(tick)},{anchor === 'bottom'
|
|
57
|
+
? plot.margins.top + plot.plotHeight
|
|
58
|
+
: plot.margins.top})"
|
|
59
|
+
>
|
|
60
|
+
<text
|
|
61
|
+
style={getBaseStyles(tick, { fill, fontSize: tickFontSize })}
|
|
62
|
+
y={(tickSize + tickPadding) * (anchor === 'bottom' ? 1 : -1)}
|
|
63
|
+
dominant-baseline={anchor === 'bottom' ? 'hanging' : 'auto'}
|
|
64
|
+
>
|
|
65
|
+
{#if typeof textLines === 'string' || textLines.length === 1}
|
|
66
|
+
{textLines}
|
|
67
|
+
{:else}
|
|
68
|
+
{#each textLines as line, i}
|
|
69
|
+
<tspan x="0" dy={i ? 12 : 0}
|
|
70
|
+
>{!prevTextLines || prevTextLines[i] !== line ? line : ''}</tspan
|
|
71
|
+
>
|
|
72
|
+
{/each}
|
|
73
|
+
{/if}
|
|
74
|
+
</text>
|
|
75
|
+
<line
|
|
76
|
+
style={getBaseStyles(tick, styleProps)}
|
|
77
|
+
y2={anchor === 'bottom' ? tickSize : -tickSize}
|
|
78
|
+
/>
|
|
79
|
+
</g>
|
|
80
|
+
{/each}
|
|
81
|
+
</g>
|
|
82
|
+
</BaseMark_AxisX>
|
|
83
|
+
|
|
84
|
+
<style>
|
|
85
|
+
text {
|
|
86
|
+
text-anchor: middle;
|
|
87
|
+
font-size: 11px;
|
|
88
|
+
|
|
89
|
+
fill: #4a4a4a;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
text.axis-title {
|
|
93
|
+
text-anchor: end;
|
|
94
|
+
}
|
|
95
|
+
.x-tick line {
|
|
96
|
+
stroke: currentColor;
|
|
97
|
+
}
|
|
98
|
+
.x-tick line.grid {
|
|
99
|
+
stroke: #d9d9d9;
|
|
100
|
+
}
|
|
101
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { AxisMarkOptions } from '../types';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: AxisMarkOptions & {
|
|
5
|
+
anchor?: "bottom" | "top" | undefined;
|
|
6
|
+
};
|
|
7
|
+
events: {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
};
|
|
10
|
+
slots: {};
|
|
11
|
+
};
|
|
12
|
+
export type AxisXProps = typeof __propDef.props;
|
|
13
|
+
export type AxisXEvents = typeof __propDef.events;
|
|
14
|
+
export type AxisXSlots = typeof __propDef.slots;
|
|
15
|
+
export default class AxisX extends SvelteComponent<AxisXProps, AxisXEvents, AxisXSlots> {
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script>import { getContext } from "svelte";
|
|
2
|
+
import BaseMark from "./BaseMark.svelte";
|
|
3
|
+
import getBaseStyles from "../helpers/getBaseStyles";
|
|
4
|
+
import { get } from "underscore";
|
|
5
|
+
const BaseMark_AxisX = BaseMark;
|
|
6
|
+
const plot = getContext("svelteplot");
|
|
7
|
+
let {
|
|
8
|
+
ticks = [],
|
|
9
|
+
anchor = "left",
|
|
10
|
+
automatic = false,
|
|
11
|
+
tickSize = 6,
|
|
12
|
+
tickPadding = 3,
|
|
13
|
+
title = null,
|
|
14
|
+
tickFormat = (d) => String(d),
|
|
15
|
+
tickFontSize = null,
|
|
16
|
+
fill = null,
|
|
17
|
+
...styleProps
|
|
18
|
+
} = $props();
|
|
19
|
+
let autoTickCount = $derived(plot.plotHeight / get(plot, "options.y.tickSpacing", 80));
|
|
20
|
+
let autoTicks = $derived(
|
|
21
|
+
ticks.length > 0 ? ticks : get(plot, "options.y.ticks", plot.yScale.ticks(autoTickCount))
|
|
22
|
+
);
|
|
23
|
+
let optionsLabel = $derived(get(plot, "options.y.label"));
|
|
24
|
+
let useTitle = $derived(
|
|
25
|
+
title || (optionsLabel === null ? null : optionsLabel === void 0 ? plot.y.autoTitle : optionsLabel)
|
|
26
|
+
);
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<BaseMark_AxisX type="axis-y" data={ticks} channels={['y']} {automatic}>
|
|
30
|
+
<g class="axis-y">
|
|
31
|
+
{#if useTitle}
|
|
32
|
+
<text x={0} y={5} class="axis-title" dominant-baseline="hanging">↑ {useTitle}</text>
|
|
33
|
+
{/if}
|
|
34
|
+
{#each autoTicks as tick}
|
|
35
|
+
<g
|
|
36
|
+
class="y-tick"
|
|
37
|
+
transform="translate({plot.margins.left +
|
|
38
|
+
(anchor === 'left' ? 0 : plot.plotWidth)},{plot.yScale(tick)})"
|
|
39
|
+
>
|
|
40
|
+
<text
|
|
41
|
+
class:is-left={anchor === 'left'}
|
|
42
|
+
style={getBaseStyles(tick, { fill, fontSize: tickFontSize })}
|
|
43
|
+
x={(tickSize + tickPadding) * (anchor === 'left' ? -1 : 1)}
|
|
44
|
+
dominant-baseline="middle">{tickFormat(tick)}</text
|
|
45
|
+
>
|
|
46
|
+
<line
|
|
47
|
+
style={getBaseStyles(tick, styleProps)}
|
|
48
|
+
x2={anchor === 'left' ? -tickSize : tickSize}
|
|
49
|
+
/>
|
|
50
|
+
</g>
|
|
51
|
+
{/each}
|
|
52
|
+
</g>
|
|
53
|
+
</BaseMark_AxisX>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
text {
|
|
57
|
+
font-size: 11px;
|
|
58
|
+
fill: #4a4a4a;
|
|
59
|
+
}
|
|
60
|
+
text.is-left {
|
|
61
|
+
text-anchor: end;
|
|
62
|
+
}
|
|
63
|
+
text.axis-title {
|
|
64
|
+
text-anchor: start;
|
|
65
|
+
}
|
|
66
|
+
.y-tick line {
|
|
67
|
+
stroke: currentColor;
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { AxisYMarkProps } from '../types';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: AxisYMarkProps;
|
|
5
|
+
events: {
|
|
6
|
+
[evt: string]: CustomEvent<any>;
|
|
7
|
+
};
|
|
8
|
+
slots: {};
|
|
9
|
+
};
|
|
10
|
+
export type AxisYProps = typeof __propDef.props;
|
|
11
|
+
export type AxisYEvents = typeof __propDef.events;
|
|
12
|
+
export type AxisYSlots = typeof __propDef.slots;
|
|
13
|
+
export default class AxisY extends SvelteComponent<AxisYProps, AxisYEvents, AxisYSlots> {
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script context="module"></script>
|
|
2
|
+
|
|
3
|
+
<script generics="T extends BaseMarkProps">import { Mark } from "../classes/Mark.svelte";
|
|
4
|
+
import { getContext } from "svelte";
|
|
5
|
+
const plot = getContext("svelteplot");
|
|
6
|
+
let { type, data = [], channels = [], children, automatic, ...rest } = $props();
|
|
7
|
+
const mark = new Mark(type, channels, automatic, { data, ...rest });
|
|
8
|
+
plot.addMark(mark);
|
|
9
|
+
$effect(() => {
|
|
10
|
+
mark.channels = new Set(channels);
|
|
11
|
+
});
|
|
12
|
+
$effect(() => {
|
|
13
|
+
mark.props = { data, ...rest };
|
|
14
|
+
});
|
|
15
|
+
$effect(() => {
|
|
16
|
+
return () => {
|
|
17
|
+
plot.removeMark(mark);
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<slot />
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { BaseMarkProps } from '../types';
|
|
3
|
+
declare class __sveltets_Render<T extends BaseMarkProps> {
|
|
4
|
+
props(): T & {
|
|
5
|
+
children?: Function | undefined;
|
|
6
|
+
};
|
|
7
|
+
events(): {} & {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
};
|
|
10
|
+
slots(): {
|
|
11
|
+
default: {};
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export type BaseMarkProps<T extends BaseMarkProps> = ReturnType<__sveltets_Render<T>['props']>;
|
|
15
|
+
export type BaseMarkEvents<T extends BaseMarkProps> = ReturnType<__sveltets_Render<T>['events']>;
|
|
16
|
+
export type BaseMarkSlots<T extends BaseMarkProps> = ReturnType<__sveltets_Render<T>['slots']>;
|
|
17
|
+
export default class BaseMark<T extends BaseMarkProps> extends SvelteComponent<BaseMarkProps<T>, BaseMarkEvents<T>, BaseMarkSlots<T>> {
|
|
18
|
+
}
|
|
19
|
+
export {};
|