layerchart 2.0.0-next.3 → 2.0.0-next.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/components/AnnotationPoint.svelte +16 -9
- package/dist/components/AnnotationRange.svelte +3 -3
- package/dist/components/Arc.svelte +2 -2
- package/dist/components/Axis.svelte +63 -14
- package/dist/components/Axis.svelte.d.ts +12 -2
- package/dist/components/Blur.svelte +5 -3
- package/dist/components/Blur.svelte.d.ts +2 -5
- package/dist/components/BrushContext.svelte +1 -1
- package/dist/components/Calendar.svelte +10 -6
- package/dist/components/Calendar.svelte.d.ts +2 -1
- package/dist/components/Chart.svelte +2 -2
- package/dist/components/Connector.svelte +2 -2
- package/dist/components/Connector.svelte.d.ts +1 -1
- package/dist/components/Ellipse.svelte +187 -0
- package/dist/components/Ellipse.svelte.d.ts +64 -0
- package/dist/components/ForceSimulation.svelte +168 -50
- package/dist/components/ForceSimulation.svelte.d.ts +80 -21
- package/dist/components/GeoPath.svelte +12 -5
- package/dist/components/GeoPoint.svelte +1 -2
- package/dist/components/GeoSpline.svelte +4 -4
- package/dist/components/GeoSpline.svelte.d.ts +1 -1
- package/dist/components/Group.svelte +2 -2
- package/dist/components/Highlight.svelte +2 -2
- package/dist/components/Hull.svelte +1 -1
- package/dist/components/Labels.svelte +3 -2
- package/dist/components/Labels.svelte.d.ts +2 -2
- package/dist/components/Legend.svelte +19 -12
- package/dist/components/Legend.svelte.d.ts +5 -5
- package/dist/components/MonthPath.svelte +14 -11
- package/dist/components/MonthPath.svelte.d.ts +4 -3
- package/dist/components/Polygon.svelte +285 -0
- package/dist/components/Polygon.svelte.d.ts +115 -0
- package/dist/components/RadialGradient.svelte +1 -3
- package/dist/components/Spline.svelte +30 -18
- package/dist/components/Spline.svelte.d.ts +12 -4
- package/dist/components/Text.svelte +62 -60
- package/dist/components/Text.svelte.d.ts +6 -0
- package/dist/components/TransformControls.svelte +16 -20
- package/dist/components/Treemap.svelte +63 -26
- package/dist/components/Treemap.svelte.d.ts +11 -11
- package/dist/components/Voronoi.svelte +51 -33
- package/dist/components/Voronoi.svelte.d.ts +3 -1
- package/dist/components/charts/ArcChart.svelte +5 -3
- package/dist/components/charts/AreaChart.svelte +11 -11
- package/dist/components/charts/BarChart.svelte +64 -53
- package/dist/components/charts/DefaultTooltip.svelte +1 -1
- package/dist/components/charts/LineChart.svelte +10 -6
- package/dist/components/charts/PieChart.svelte +5 -3
- package/dist/components/charts/ScatterChart.svelte +2 -3
- package/dist/components/charts/utils.svelte.d.ts +2 -2
- package/dist/components/charts/utils.svelte.js +5 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +5 -1
- package/dist/components/layout/Canvas.svelte +67 -49
- package/dist/components/layout/Canvas.svelte.d.ts +6 -0
- package/dist/components/layout/Layer.svelte +6 -4
- package/dist/components/layout/Layer.svelte.d.ts +6 -4
- package/dist/components/tooltip/Tooltip.svelte +14 -7
- package/dist/components/tooltip/TooltipContext.svelte +78 -34
- package/dist/components/tooltip/TooltipContext.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipHeader.svelte +5 -4
- package/dist/components/tooltip/TooltipHeader.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipItem.svelte +5 -4
- package/dist/components/tooltip/TooltipItem.svelte.d.ts +3 -3
- package/dist/components/tooltip/TooltipList.svelte +1 -1
- package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
- package/dist/docs/Blockquote.svelte +6 -4
- package/dist/docs/Blockquote.svelte.d.ts +4 -19
- package/dist/docs/Code.svelte +20 -12
- package/dist/docs/Code.svelte.d.ts +9 -23
- package/dist/docs/Header1.svelte +4 -2
- package/dist/docs/Header1.svelte.d.ts +4 -28
- package/dist/docs/Json.svelte +11 -3
- package/dist/docs/Json.svelte.d.ts +9 -21
- package/dist/docs/Layout.svelte +10 -7
- package/dist/docs/Layout.svelte.d.ts +4 -19
- package/dist/docs/Link.svelte +7 -3
- package/dist/docs/Link.svelte.d.ts +4 -38
- package/dist/docs/Preview.svelte +6 -3
- package/dist/docs/TilesetField.svelte +20 -19
- package/dist/docs/TilesetField.svelte.d.ts +5 -22
- package/dist/docs/ViewSourceButton.svelte +9 -6
- package/dist/docs/ViewSourceButton.svelte.d.ts +7 -21
- package/dist/utils/arcText.svelte.js +4 -4
- package/dist/utils/array.d.ts +11 -0
- package/dist/utils/array.js +23 -0
- package/dist/utils/array.test.d.ts +1 -0
- package/dist/utils/array.test.js +200 -0
- package/dist/utils/canvas.d.ts +77 -0
- package/dist/utils/canvas.js +105 -41
- package/dist/utils/genData.d.ts +14 -0
- package/dist/utils/genData.js +24 -6
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/path.d.ts +10 -0
- package/dist/utils/path.js +30 -0
- package/dist/utils/scales.svelte.d.ts +3 -2
- package/dist/utils/scales.svelte.js +7 -3
- package/dist/utils/shape.d.ts +43 -0
- package/dist/utils/shape.js +59 -0
- package/dist/utils/string.d.ts +49 -0
- package/dist/utils/string.js +4 -2
- package/dist/utils/ticks.d.ts +15 -4
- package/dist/utils/ticks.js +140 -159
- package/dist/utils/ticks.test.js +6 -16
- package/dist/utils/treemap.d.ts +1 -1
- package/package.json +27 -25
- package/dist/utils/object.js +0 -2
package/dist/utils/path.js
CHANGED
|
@@ -36,6 +36,36 @@ export function spikePath({ x, y, width, height, }) {
|
|
|
36
36
|
`;
|
|
37
37
|
return pathData;
|
|
38
38
|
}
|
|
39
|
+
/** Create rounded polygon path
|
|
40
|
+
*
|
|
41
|
+
* @param coords - Array of points (x, y)
|
|
42
|
+
* @param radius - Radius of the curve
|
|
43
|
+
* @returns String of path data
|
|
44
|
+
*/
|
|
45
|
+
export function roundedPolygonPath(coords, radius) {
|
|
46
|
+
if (radius === 0) {
|
|
47
|
+
// Simple polygon with straight lines
|
|
48
|
+
return `M${coords[0].x},${coords[0].y}${coords
|
|
49
|
+
.slice(1)
|
|
50
|
+
.map((p) => `L${p.x},${p.y}`)
|
|
51
|
+
.join('')}Z`;
|
|
52
|
+
}
|
|
53
|
+
let path = '';
|
|
54
|
+
const length = coords.length + 1;
|
|
55
|
+
for (let i = 0; i < length; i++) {
|
|
56
|
+
const a = coords[i % coords.length];
|
|
57
|
+
const b = coords[(i + 1) % coords.length];
|
|
58
|
+
const t = Math.min(radius / Math.hypot(b.x - a.x, b.y - a.y), 0.5);
|
|
59
|
+
if (i == 0)
|
|
60
|
+
path += `M${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`;
|
|
61
|
+
if (i > 0)
|
|
62
|
+
path += `Q${a.x},${a.y} ${a.x * (1 - t) + b.x * t},${a.y * (1 - t) + b.y * t}`;
|
|
63
|
+
if (i < length - 1)
|
|
64
|
+
path += `L${a.x * t + b.x * (1 - t)},${a.y * t + b.y * (1 - t)}`;
|
|
65
|
+
}
|
|
66
|
+
path += 'Z';
|
|
67
|
+
return path;
|
|
68
|
+
}
|
|
39
69
|
/** Flatten all `y` coordinates to `0` */
|
|
40
70
|
export function flattenPathData(pathData, yOverride = 0) {
|
|
41
71
|
let result = pathData;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ScaleBand } from 'd3-scale';
|
|
1
|
+
import { type ScaleBand, type ScaleTime } from 'd3-scale';
|
|
2
2
|
import { type MotionProp, type MotionOptions, type SpringOptions, type TweenOptions } from './motion.svelte.js';
|
|
3
3
|
import type { Accessor } from './common.js';
|
|
4
4
|
import type { OnlyObjects } from './types.js';
|
|
@@ -23,6 +23,8 @@ export type AnyScale<TInput extends SingleDomainType = any, TOutput extends Sing
|
|
|
23
23
|
thresholds?: () => TInput[];
|
|
24
24
|
quantiles?: () => TInput[];
|
|
25
25
|
};
|
|
26
|
+
export declare function isScaleBand(scale: AnyScale<any, any>): scale is ScaleBand<any>;
|
|
27
|
+
export declare function isScaleTime(scale: AnyScale<any, any>): scale is ScaleTime<any, any>;
|
|
26
28
|
export declare function getRange(scale: any): any[];
|
|
27
29
|
export type SingleDomainType = number | string | Date | null | undefined;
|
|
28
30
|
export type DomainType = (number | string | Date | null | undefined)[] | null | undefined;
|
|
@@ -45,7 +47,6 @@ export declare function createMotionScale<Domain, Range>(scale: AnyScale, motion
|
|
|
45
47
|
* https://gist.github.com/LuisSevillano/d53a1dc529eef518780c6df99613e2fd
|
|
46
48
|
*/
|
|
47
49
|
export declare function scaleBandInvert(scale: ScaleBand<any>): (value: number) => any;
|
|
48
|
-
export declare function isScaleBand(scale: AnyScale<any, any>): scale is ScaleBand<any>;
|
|
49
50
|
/**
|
|
50
51
|
* Generic way to invert a scale value, handling scaleBand and continuous scales (linear, time, etc).
|
|
51
52
|
* Useful to map mouse event location (x,y) to domain value
|
|
@@ -5,6 +5,13 @@ import { Spring, Tween } from 'svelte/motion';
|
|
|
5
5
|
function isAnyScale(scale) {
|
|
6
6
|
return typeof scale === 'function' && typeof scale.range === 'function';
|
|
7
7
|
}
|
|
8
|
+
export function isScaleBand(scale) {
|
|
9
|
+
return typeof scale.bandwidth === 'function';
|
|
10
|
+
}
|
|
11
|
+
export function isScaleTime(scale) {
|
|
12
|
+
const domain = scale.domain();
|
|
13
|
+
return domain[0] instanceof Date || domain[1] instanceof Date;
|
|
14
|
+
}
|
|
8
15
|
export function getRange(scale) {
|
|
9
16
|
if (isAnyScale(scale)) {
|
|
10
17
|
return scale.range();
|
|
@@ -54,9 +61,6 @@ export function scaleBandInvert(scale) {
|
|
|
54
61
|
return domain[Math.max(0, Math.min(index, domain.length - 1))];
|
|
55
62
|
};
|
|
56
63
|
}
|
|
57
|
-
export function isScaleBand(scale) {
|
|
58
|
-
return typeof scale.bandwidth === 'function';
|
|
59
|
-
}
|
|
60
64
|
/**
|
|
61
65
|
* Generic way to invert a scale value, handling scaleBand and continuous scales (linear, time, etc).
|
|
62
66
|
* Useful to map mouse event location (x,y) to domain value
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Get points to create a polygon with given number of points and radius
|
|
2
|
+
*
|
|
3
|
+
* @param count - Number of points
|
|
4
|
+
* @param radius - Radius of the polygon
|
|
5
|
+
* @returns Array of points (angle, radius)
|
|
6
|
+
*/
|
|
7
|
+
export declare function polygonPoints(count: number, radius: number, rotate?: number): {
|
|
8
|
+
angle: number;
|
|
9
|
+
radius: number;
|
|
10
|
+
}[];
|
|
11
|
+
/** Create polygon
|
|
12
|
+
*
|
|
13
|
+
* @param cx - Center x coordinate
|
|
14
|
+
* @param cy - Center y coordinate
|
|
15
|
+
* @param count - Number of points
|
|
16
|
+
* @param radius - Radius of the polygon
|
|
17
|
+
* @param rotate - Rotation of the polygon (degrees)
|
|
18
|
+
* @param inset - Percent to inset odd points (<1 inset, >1 outset)
|
|
19
|
+
* @param scaleX - Horizontal stretch factor
|
|
20
|
+
* @param scaleY - Vertical stretch factor
|
|
21
|
+
* @param skewX - Skew angle in degrees along the X axis
|
|
22
|
+
* @param skewY - Skew angle in degrees along the Y axis
|
|
23
|
+
* @param tiltX - Tilt factor for x-coordinates (0 = no tilt, positive moves points top => down, negative moves points bottom => up)
|
|
24
|
+
* @param tiltY - Tilt factor for y-coordinates (0 = no tilt, positive moves points left => right, negative moves points right => left)
|
|
25
|
+
* @returns Array of points (x, y)
|
|
26
|
+
*/
|
|
27
|
+
export declare function polygon(options: {
|
|
28
|
+
cx: number;
|
|
29
|
+
cy: number;
|
|
30
|
+
count: number;
|
|
31
|
+
radius: number;
|
|
32
|
+
rotate?: number;
|
|
33
|
+
inset?: number;
|
|
34
|
+
scaleX?: number;
|
|
35
|
+
scaleY?: number;
|
|
36
|
+
skewX?: number;
|
|
37
|
+
skewY?: number;
|
|
38
|
+
tiltX?: number;
|
|
39
|
+
tiltY?: number;
|
|
40
|
+
}): {
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
}[];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { range } from 'd3-array';
|
|
2
|
+
import { degreesToRadians } from './math.js';
|
|
3
|
+
/** Get points to create a polygon with given number of points and radius
|
|
4
|
+
*
|
|
5
|
+
* @param count - Number of points
|
|
6
|
+
* @param radius - Radius of the polygon
|
|
7
|
+
* @returns Array of points (angle, radius)
|
|
8
|
+
*/
|
|
9
|
+
export function polygonPoints(count, radius, rotate = 0) {
|
|
10
|
+
const angle = 360 / count;
|
|
11
|
+
return range(count).map((index) => {
|
|
12
|
+
return {
|
|
13
|
+
angle: degreesToRadians(angle * index) + degreesToRadians(rotate),
|
|
14
|
+
radius,
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** Create polygon
|
|
19
|
+
*
|
|
20
|
+
* @param cx - Center x coordinate
|
|
21
|
+
* @param cy - Center y coordinate
|
|
22
|
+
* @param count - Number of points
|
|
23
|
+
* @param radius - Radius of the polygon
|
|
24
|
+
* @param rotate - Rotation of the polygon (degrees)
|
|
25
|
+
* @param inset - Percent to inset odd points (<1 inset, >1 outset)
|
|
26
|
+
* @param scaleX - Horizontal stretch factor
|
|
27
|
+
* @param scaleY - Vertical stretch factor
|
|
28
|
+
* @param skewX - Skew angle in degrees along the X axis
|
|
29
|
+
* @param skewY - Skew angle in degrees along the Y axis
|
|
30
|
+
* @param tiltX - Tilt factor for x-coordinates (0 = no tilt, positive moves points top => down, negative moves points bottom => up)
|
|
31
|
+
* @param tiltY - Tilt factor for y-coordinates (0 = no tilt, positive moves points left => right, negative moves points right => left)
|
|
32
|
+
* @returns Array of points (x, y)
|
|
33
|
+
*/
|
|
34
|
+
export function polygon(options) {
|
|
35
|
+
const { cx, cy, count, radius, rotate = 0, inset = 1, scaleX = 1, scaleY = 1, skewX = 0, skewY = 0, tiltX = 0, tiltY = 0, } = options;
|
|
36
|
+
const skewXRad = degreesToRadians(skewX);
|
|
37
|
+
const skewYRad = degreesToRadians(skewY);
|
|
38
|
+
return polygonPoints(count, radius, rotate).map(({ angle, radius }, i) => {
|
|
39
|
+
// inset
|
|
40
|
+
const insetScale = i % 2 == 0 ? 1 : 1 - inset;
|
|
41
|
+
// scale
|
|
42
|
+
let x = radius * insetScale * Math.cos(angle) * scaleX;
|
|
43
|
+
let y = radius * insetScale * Math.sin(angle) * scaleY;
|
|
44
|
+
// tilt
|
|
45
|
+
const normalizedY = (y + radius) / (2 * radius);
|
|
46
|
+
const normalizedX = (x + radius) / (2 * radius);
|
|
47
|
+
const tiltScaleX = tiltX > 0 ? 1 + tiltX * (1 - normalizedY) : 1 - tiltX * normalizedY;
|
|
48
|
+
const tiltScaleY = tiltY > 0 ? 1 + tiltY * (1 - normalizedX) : 1 - tiltY * normalizedX;
|
|
49
|
+
x *= tiltScaleX;
|
|
50
|
+
y *= tiltScaleY;
|
|
51
|
+
// skew
|
|
52
|
+
const xSkewed = x + Math.tan(skewXRad) * y;
|
|
53
|
+
const ySkewed = y + Math.tan(skewYRad) * x;
|
|
54
|
+
return {
|
|
55
|
+
x: cx + xSkewed,
|
|
56
|
+
y: cy + ySkewed,
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export declare const getStringWidth: any;
|
|
2
|
+
export type RasterizeTextOptions = {
|
|
3
|
+
fontSize?: string;
|
|
4
|
+
fontWeight?: number;
|
|
5
|
+
fontFamily?: string;
|
|
6
|
+
textAlign?: CanvasTextAlign;
|
|
7
|
+
textBaseline?: CanvasTextBaseline;
|
|
8
|
+
spacing?: number;
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
x?: number;
|
|
12
|
+
y?: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function rasterizeText(text: string, options?: RasterizeTextOptions): number[][];
|
|
15
|
+
export declare function toTitleCase(str: string): string;
|
|
16
|
+
export type TruncateTextOptions = {
|
|
17
|
+
/**
|
|
18
|
+
* The maximum pixel width (optional if maxChars is provided).
|
|
19
|
+
*/
|
|
20
|
+
maxWidth?: number;
|
|
21
|
+
/**
|
|
22
|
+
* CSS style for width calculation
|
|
23
|
+
*/
|
|
24
|
+
style?: CSSStyleDeclaration;
|
|
25
|
+
/**
|
|
26
|
+
* The maximum character count
|
|
27
|
+
*/
|
|
28
|
+
maxChars?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Where to place the ellipsis: 'start', 'middle', or 'end'
|
|
31
|
+
*
|
|
32
|
+
* @default 'end'
|
|
33
|
+
*/
|
|
34
|
+
position?: 'start' | 'middle' | 'end';
|
|
35
|
+
/**
|
|
36
|
+
* The character(s) to use as the ellipsis
|
|
37
|
+
*
|
|
38
|
+
* @default '…'
|
|
39
|
+
*/
|
|
40
|
+
ellipsis?: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Truncates a string to fit within a specified pixel width or character count.
|
|
44
|
+
* If the string's width exceeds the maxWidth, it will be truncated. If the character
|
|
45
|
+
* count exceeds maxChars, it will also be truncated.
|
|
46
|
+
*
|
|
47
|
+
* The ellipsis can be placed at the start, middle, or end of the string.
|
|
48
|
+
*/
|
|
49
|
+
export declare function truncateText(text: string, { position, ellipsis, maxWidth, style, maxChars }: TruncateTextOptions): string;
|
package/dist/utils/string.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import memoize from 'memoize';
|
|
2
2
|
const MEASUREMENT_ELEMENT_ID = '__text_measurement_id';
|
|
3
3
|
function _getStringWidth(str, style) {
|
|
4
4
|
try {
|
|
@@ -24,7 +24,9 @@ function _getStringWidth(str, style) {
|
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
export const getStringWidth = memoize(_getStringWidth,
|
|
27
|
+
export const getStringWidth = memoize(_getStringWidth, {
|
|
28
|
+
cacheKey: ([str, style]) => `${str}_${JSON.stringify(style)}`,
|
|
29
|
+
});
|
|
28
30
|
export function rasterizeText(text, options = {}) {
|
|
29
31
|
const fontSize = options.fontSize ?? '200px';
|
|
30
32
|
const fontWeight = options.fontWeight ?? 600;
|
package/dist/utils/ticks.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { type TimeInterval } from 'd3-time';
|
|
2
|
+
import { Duration, type FormatType, type FormatConfig } from '@layerstack/utils';
|
|
2
3
|
import { type AnyScale } from './scales.svelte.js';
|
|
3
|
-
|
|
4
|
-
export declare function
|
|
5
|
-
|
|
4
|
+
import type { AxisProps } from '../components/Axis.svelte';
|
|
5
|
+
export declare function getDurationFormat(duration: Duration, options?: {
|
|
6
|
+
multiline?: boolean;
|
|
7
|
+
placement?: AxisProps['placement'];
|
|
8
|
+
}): (date: Date, i: number) => string;
|
|
6
9
|
export type TicksConfig = number | any[] | ((scale: AnyScale) => any[] | undefined) | {
|
|
7
10
|
interval: TimeInterval | null;
|
|
8
11
|
} | null;
|
|
9
|
-
export declare function resolveTickVals(scale: AnyScale, ticks?: TicksConfig,
|
|
12
|
+
export declare function resolveTickVals(scale: AnyScale, ticks?: TicksConfig, count?: number): any[];
|
|
13
|
+
export declare function resolveTickFormat(options: {
|
|
14
|
+
scale: AnyScale;
|
|
15
|
+
ticks?: TicksConfig;
|
|
16
|
+
count?: number;
|
|
17
|
+
formatType?: FormatType | FormatConfig;
|
|
18
|
+
multiline?: boolean;
|
|
19
|
+
placement?: AxisProps['placement'];
|
|
20
|
+
}): (date: Date, i: number) => string;
|
package/dist/utils/ticks.js
CHANGED
|
@@ -1,183 +1,164 @@
|
|
|
1
|
-
import { timeYear, timeMonth,
|
|
2
|
-
import { format } from '
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
predicate: (duration) => duration.years > 1,
|
|
14
|
-
interval: timeYear.every(1),
|
|
15
|
-
format: (date) => formatDate(date, PeriodType.CalendarYear, { variant: 'short' }),
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
predicate: (duration) => duration.years,
|
|
19
|
-
interval: timeMonth.every(1),
|
|
20
|
-
format: (date) => formatDate(date, PeriodType.Month, { variant: 'short' }),
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
predicate: (duration) => duration.days > 30,
|
|
24
|
-
interval: timeMonth.every(1),
|
|
25
|
-
format: (date) => formatDate(date, PeriodType.Month, { variant: 'short' }),
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
predicate: (duration) => duration.days,
|
|
29
|
-
interval: timeDay.every(1),
|
|
30
|
-
format: (date) => formatDate(date, PeriodType.Day, { variant: 'short' }),
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
predicate: (duration) => duration.hours,
|
|
34
|
-
interval: timeHour.every(1),
|
|
35
|
-
format: (date) => format(date, 'h:mm a'),
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
predicate: (duration) => duration.minutes > 10,
|
|
39
|
-
interval: timeMinute.every(10),
|
|
40
|
-
format: (date) => format(date, 'h:mm a'),
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
predicate: (duration) => duration.minutes,
|
|
44
|
-
interval: timeMinute.every(1),
|
|
45
|
-
format: (date) => format(date, 'h:mm a'),
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
predicate: (duration) => duration.seconds > 10,
|
|
49
|
-
interval: timeSecond.every(10),
|
|
50
|
-
format: (date) => format(date, 'h:mm:ss'),
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
predicate: (duration) => duration.seconds,
|
|
54
|
-
interval: timeSecond.every(1),
|
|
55
|
-
format: (date) => format(date, 'h:mm:ss'),
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
predicate: (duration) => true, // 0 or more milliseconds
|
|
59
|
-
interval: timeMillisecond.every(100),
|
|
60
|
-
format: (date) => format(date, 'h:mm:ss.SSS'),
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
const minorTicks = [
|
|
64
|
-
{
|
|
65
|
-
predicate: (duration) => duration == null, // Unknown
|
|
66
|
-
interval: timeYear.every(1), // Better than rendering a lot of items
|
|
67
|
-
format: (date) => date.toString(),
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
predicate: (duration) => duration.years,
|
|
71
|
-
interval: timeMonth.every(1),
|
|
72
|
-
format: (date) => formatDate(date, PeriodType.Month, { variant: 'short' }),
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
predicate: (duration) => duration.days > 90,
|
|
76
|
-
interval: timeMonth.every(1),
|
|
77
|
-
format: (date) => formatDate(date, PeriodType.Month, { variant: 'short' }),
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
predicate: (duration) => duration.days > 30,
|
|
81
|
-
interval: timeWeek.every(1),
|
|
82
|
-
format: (date) => formatDate(date, PeriodType.WeekSun, { variant: 'short' }),
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
predicate: (duration) => duration.days > 7,
|
|
86
|
-
interval: timeDay.every(1),
|
|
87
|
-
format: (date) => formatDate(date, PeriodType.Day, { variant: 'short' }),
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
predicate: (duration) => duration.days > 3,
|
|
91
|
-
interval: timeHour.every(8),
|
|
92
|
-
format: (date) => format(date, 'h:mm a'),
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
predicate: (duration) => duration.days,
|
|
96
|
-
interval: timeHour.every(1),
|
|
97
|
-
format: (date) => format(date, 'h:mm a'),
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
predicate: (duration) => duration.hours,
|
|
101
|
-
interval: timeMinute.every(15),
|
|
102
|
-
format: (date) => format(date, 'h:mm a'),
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
predicate: (duration) => duration.minutes > 10,
|
|
106
|
-
interval: timeMinute.every(10),
|
|
107
|
-
format: (date) => format(date, 'h:mm a'),
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
predicate: (duration) => duration.minutes > 2,
|
|
111
|
-
interval: timeMinute.every(1),
|
|
112
|
-
format: (date) => format(date, 'h:mm a'),
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
predicate: (duration) => duration.minutes,
|
|
116
|
-
interval: timeSecond.every(10),
|
|
117
|
-
format: (date) => format(date, 'h:mm:ss'),
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
predicate: (duration) => duration.seconds,
|
|
121
|
-
interval: timeSecond.every(1),
|
|
122
|
-
format: (date) => format(date, 'h:mm:ss'),
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
predicate: (duration) => true, // 0 or more milliseconds
|
|
126
|
-
interval: timeMillisecond.every(10),
|
|
127
|
-
format: (date) => format(date, 'h:mm:ss.SSS'),
|
|
128
|
-
},
|
|
129
|
-
];
|
|
130
|
-
export function getMajorTicks(start, end) {
|
|
131
|
-
const duration = getDuration(start, end);
|
|
132
|
-
for (var t of majorTicks) {
|
|
133
|
-
if (t.predicate(duration)) {
|
|
134
|
-
return t.interval;
|
|
1
|
+
import { timeYear, timeMonth, timeDay, timeTicks } from 'd3-time';
|
|
2
|
+
import { format, Duration, isLiteralObject, DateToken, } from '@layerstack/utils';
|
|
3
|
+
import { isScaleBand, isScaleTime } from './scales.svelte.js';
|
|
4
|
+
export function getDurationFormat(duration, options = {
|
|
5
|
+
multiline: false,
|
|
6
|
+
}) {
|
|
7
|
+
const { multiline = false, placement = 'bottom' } = options;
|
|
8
|
+
return function (date, i) {
|
|
9
|
+
let result = '';
|
|
10
|
+
if (+duration >= +new Duration({ duration: { years: 1 } })) {
|
|
11
|
+
// Year
|
|
12
|
+
result = format(date, 'year');
|
|
135
13
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
14
|
+
else if (+duration >= +new Duration({ duration: { days: 28 } })) {
|
|
15
|
+
// Month
|
|
16
|
+
const isFirst = i === 0 || +timeYear.floor(date) === +date;
|
|
17
|
+
if (multiline) {
|
|
18
|
+
result = [format(date, 'month', { variant: 'short' }), isFirst && format(date, 'year')];
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
result =
|
|
22
|
+
format(date, 'month', { variant: 'short' }) +
|
|
23
|
+
(isFirst ? ` '${format(date, 'year', { variant: 'short' })}` : '');
|
|
24
|
+
}
|
|
144
25
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
26
|
+
else if (+duration >= +new Duration({ duration: { days: 1 } })) {
|
|
27
|
+
// Day
|
|
28
|
+
const isFirst = i === 0 || date.getDate() <= duration.days;
|
|
29
|
+
if (multiline) {
|
|
30
|
+
result = [
|
|
31
|
+
format(date, 'custom', { custom: DateToken.DayOfMonth_numeric }),
|
|
32
|
+
isFirst && format(date, 'month', { variant: 'short' }),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
result = format(date, 'day', { variant: 'short' });
|
|
37
|
+
}
|
|
153
38
|
}
|
|
154
|
-
|
|
155
|
-
|
|
39
|
+
else if (+duration >= +new Duration({ duration: { hours: 1 } })) {
|
|
40
|
+
// Hours
|
|
41
|
+
const isFirst = i === 0 || +timeDay.floor(date) === +date;
|
|
42
|
+
if (multiline) {
|
|
43
|
+
result = [
|
|
44
|
+
format(date, 'custom', { custom: DateToken.Hour_numeric }),
|
|
45
|
+
isFirst && format(date, 'day', { variant: 'short' }),
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
result = isFirst
|
|
50
|
+
? format(date, 'day', { variant: 'short' })
|
|
51
|
+
: format(date, 'custom', { custom: DateToken.Hour_numeric });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (+duration >= +new Duration({ duration: { minutes: 1 } })) {
|
|
55
|
+
// Minutes
|
|
56
|
+
const isFirst = i === 0 || +timeDay.floor(date) === +date;
|
|
57
|
+
if (multiline) {
|
|
58
|
+
result = [
|
|
59
|
+
format(date, 'time', { variant: 'short' }),
|
|
60
|
+
isFirst && format(date, 'day', { variant: 'short' }),
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
result = format(date, 'time', { variant: 'short' });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (+duration >= +new Duration({ duration: { seconds: 1 } })) {
|
|
68
|
+
// Seconds
|
|
69
|
+
const isFirst = i === 0 || +timeDay.floor(date) === +date;
|
|
70
|
+
result = [
|
|
71
|
+
format(date, 'time'),
|
|
72
|
+
multiline && isFirst && format(date, 'day', { variant: 'short' }),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
else if (+duration >= +new Duration({ duration: { milliseconds: 1 } })) {
|
|
76
|
+
// Milliseconds
|
|
77
|
+
const isFirst = i === 0 || +timeDay.floor(date) === +date;
|
|
78
|
+
result = [
|
|
79
|
+
format(date, 'custom', {
|
|
80
|
+
custom: [
|
|
81
|
+
DateToken.Hour_2Digit,
|
|
82
|
+
DateToken.Minute_2Digit,
|
|
83
|
+
DateToken.Second_2Digit,
|
|
84
|
+
DateToken.MiliSecond_3,
|
|
85
|
+
DateToken.Hour_woAMPM,
|
|
86
|
+
],
|
|
87
|
+
}),
|
|
88
|
+
multiline && isFirst && format(date, 'day', { variant: 'short' }),
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
result = date.toString();
|
|
93
|
+
}
|
|
94
|
+
if (Array.isArray(result)) {
|
|
95
|
+
switch (placement) {
|
|
96
|
+
case 'top':
|
|
97
|
+
return result.filter(Boolean).reverse().join('\n');
|
|
98
|
+
case 'bottom':
|
|
99
|
+
return result.filter(Boolean).join('\n');
|
|
100
|
+
case 'left':
|
|
101
|
+
return result.filter(Boolean).reverse().join(' ');
|
|
102
|
+
case 'right':
|
|
103
|
+
return result.filter(Boolean).join(' ');
|
|
104
|
+
default:
|
|
105
|
+
return result.filter(Boolean).join('\n');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
156
112
|
}
|
|
157
|
-
export function resolveTickVals(scale, ticks,
|
|
113
|
+
export function resolveTickVals(scale, ticks, count) {
|
|
114
|
+
// Explicit ticks
|
|
158
115
|
if (Array.isArray(ticks))
|
|
159
116
|
return ticks;
|
|
117
|
+
// Function
|
|
160
118
|
if (typeof ticks === 'function')
|
|
161
119
|
return ticks(scale) ?? [];
|
|
120
|
+
// Interval
|
|
162
121
|
if (isLiteralObject(ticks) && 'interval' in ticks) {
|
|
163
122
|
if (ticks.interval === null || !('ticks' in scale) || typeof scale.ticks !== 'function') {
|
|
164
123
|
return []; // Explicitly return empty array for null interval or invalid scale
|
|
165
124
|
}
|
|
166
125
|
return scale.ticks(ticks.interval);
|
|
167
126
|
}
|
|
127
|
+
// Band (use domain)
|
|
168
128
|
if (isScaleBand(scale)) {
|
|
169
129
|
return ticks && typeof ticks === 'number'
|
|
170
130
|
? scale.domain().filter((_, i) => i % ticks === 0)
|
|
171
131
|
: scale.domain();
|
|
172
132
|
}
|
|
133
|
+
// Ticks from scale
|
|
173
134
|
if (scale.ticks && typeof scale.ticks === 'function') {
|
|
174
|
-
|
|
175
|
-
return scale.ticks(ticks ?? (placement === 'left' || placement === 'right' ? 4 : undefined));
|
|
176
|
-
}
|
|
177
|
-
return scale.ticks(ticks);
|
|
135
|
+
return scale.ticks(count ?? (typeof ticks === 'number' ? ticks : undefined));
|
|
178
136
|
}
|
|
179
137
|
return [];
|
|
180
138
|
}
|
|
181
|
-
function
|
|
182
|
-
|
|
139
|
+
export function resolveTickFormat(options) {
|
|
140
|
+
const { scale, ticks, count, formatType, multiline, placement } = options;
|
|
141
|
+
// Explicit format
|
|
142
|
+
if (formatType) {
|
|
143
|
+
// @ts-expect-error - improve types
|
|
144
|
+
return (tick) => format(tick, formatType);
|
|
145
|
+
}
|
|
146
|
+
// Time scale
|
|
147
|
+
if (isScaleTime(scale) && count) {
|
|
148
|
+
if (isLiteralObject(ticks) && 'interval' in ticks && ticks.interval != null) {
|
|
149
|
+
const start = ticks.interval.floor(new Date());
|
|
150
|
+
const end = ticks.interval.ceil(new Date());
|
|
151
|
+
return getDurationFormat(new Duration({ start, end }), { multiline, placement });
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Compare first 2 ticks to determine duration between ticks for formatting
|
|
155
|
+
const [start, end] = timeTicks(scale.domain()[0], scale.domain()[1], count);
|
|
156
|
+
return getDurationFormat(new Duration({ start, end }), { multiline, placement });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Format from scale
|
|
160
|
+
if (scale.tickFormat) {
|
|
161
|
+
return scale.tickFormat(count);
|
|
162
|
+
}
|
|
163
|
+
return (tick) => `${tick}`;
|
|
183
164
|
}
|
package/dist/utils/ticks.test.js
CHANGED
|
@@ -35,33 +35,23 @@ describe('resolveTickVals', () => {
|
|
|
35
35
|
const scale = { domain: mockDomain, bandwidth: vi.fn() };
|
|
36
36
|
expect(resolveTickVals(scale)).toEqual(['a', 'b', 'c', 'd', 'e']);
|
|
37
37
|
});
|
|
38
|
-
it('uses default 4 ticks for left placement', () => {
|
|
39
|
-
const scale = { ticks: vi.fn(() => [1, 2, 3, 4]) };
|
|
40
|
-
expect(resolveTickVals(scale, undefined, 'left')).toEqual([1, 2, 3, 4]);
|
|
41
|
-
expect(scale.ticks).toHaveBeenCalledWith(4);
|
|
42
|
-
});
|
|
43
|
-
it('uses default 4 ticks for right placement', () => {
|
|
44
|
-
const scale = { ticks: vi.fn(() => [1, 2, 3, 4]) };
|
|
45
|
-
expect(resolveTickVals(scale, undefined, 'right')).toEqual([1, 2, 3, 4]);
|
|
46
|
-
expect(scale.ticks).toHaveBeenCalledWith(4);
|
|
47
|
-
});
|
|
48
38
|
it('uses undefined for non-left/right placement', () => {
|
|
49
|
-
const scale = { ticks: vi.fn(() => [1, 2]) };
|
|
50
|
-
expect(resolveTickVals(scale, undefined,
|
|
39
|
+
const scale = { domain: mockDomain, ticks: vi.fn(() => [1, 2]) };
|
|
40
|
+
expect(resolveTickVals(scale, undefined, undefined)).toEqual([1, 2]);
|
|
51
41
|
expect(scale.ticks).toHaveBeenCalledWith(undefined);
|
|
52
42
|
});
|
|
53
43
|
it('passes number ticks to scale.ticks', () => {
|
|
54
|
-
const scale = { ticks: vi.fn(() => [10, 20]) };
|
|
44
|
+
const scale = { domain: mockDomain, ticks: vi.fn(() => [10, 20]) };
|
|
55
45
|
expect(resolveTickVals(scale, 5)).toEqual([10, 20]);
|
|
56
46
|
expect(scale.ticks).toHaveBeenCalledWith(5);
|
|
57
47
|
});
|
|
58
48
|
it('returns empty array for scale without ticks', () => {
|
|
59
|
-
const scale = {};
|
|
49
|
+
const scale = { domain: mockDomain };
|
|
60
50
|
expect(resolveTickVals(scale, 5)).toEqual([]);
|
|
61
51
|
});
|
|
62
52
|
it('handles null ticks with placement', () => {
|
|
63
|
-
const scale = { ticks: vi.fn(() => [1, 2, 3]) };
|
|
64
|
-
expect(resolveTickVals(scale, null,
|
|
53
|
+
const scale = { domain: mockDomain, ticks: vi.fn(() => [1, 2, 3]) };
|
|
54
|
+
expect(resolveTickVals(scale, null, undefined)).toEqual([1, 2, 3]);
|
|
65
55
|
expect(scale.ticks).toHaveBeenCalledWith(undefined);
|
|
66
56
|
});
|
|
67
57
|
});
|
package/dist/utils/treemap.d.ts
CHANGED
|
@@ -9,5 +9,5 @@ export declare function aspectTile(tile: TileFunc, width: number, height: number
|
|
|
9
9
|
/**
|
|
10
10
|
* Show if the node (a) is a child of the selected (b), or any parent above selected
|
|
11
11
|
*/
|
|
12
|
-
export declare function isNodeVisible(a: HierarchyNode<any>, b: HierarchyNode<any> | null): boolean;
|
|
12
|
+
export declare function isNodeVisible(a: HierarchyNode<any>, b: HierarchyNode<any> | null | undefined): boolean;
|
|
13
13
|
export {};
|