svelteplot 0.11.0-pr-514.0 → 0.11.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/dist/Mark.svelte CHANGED
@@ -297,7 +297,12 @@
297
297
  : plot.scales[scale].fn(value)
298
298
  : value;
299
299
 
300
- out.valid = out.valid && (scale === 'color' || isValid(value));
300
+ out.valid =
301
+ out.valid &&
302
+ (scale === 'color' ||
303
+ scale === 'fx' ||
304
+ scale === 'fy' ||
305
+ isValid(value));
301
306
 
302
307
  // apply dx/dy transform
303
308
  (out as any)[channel] =
package/dist/constants.js CHANGED
@@ -68,6 +68,7 @@ export const VALID_SCALE_TYPES = {
68
68
  'log',
69
69
  'symlog',
70
70
  'time',
71
+ 'utc',
71
72
  'ordinal',
72
73
  'band',
73
74
  'point',
@@ -80,6 +81,7 @@ export const VALID_SCALE_TYPES = {
80
81
  'log',
81
82
  'symlog',
82
83
  'time',
84
+ 'utc',
83
85
  'ordinal',
84
86
  'band',
85
87
  'point',
@@ -316,8 +316,8 @@
316
316
  const colorSymbolRedundant =
317
317
  scales.color.uniqueScaleProps?.size === 1 &&
318
318
  scales.symbol.uniqueScaleProps?.size === 1 &&
319
- [...scales.color.uniqueScaleProps?.values()][0] ===
320
- [...scales.symbol.uniqueScaleProps?.values()][0];
319
+ [...(scales.color.uniqueScaleProps?.values() ?? [])][0] ===
320
+ [...(scales.symbol.uniqueScaleProps?.values() ?? [])][0];
321
321
  return {
322
322
  options: plotOptions,
323
323
  width,
@@ -1,4 +1,4 @@
1
- import { scaleBand, scaleDiverging, scaleDivergingLog, scaleDivergingPow, scaleDivergingSqrt, scaleDivergingSymlog, scaleLinear, scaleLog, scaleOrdinal, scalePoint, scalePow, scaleQuantile, scaleQuantize, scaleSequential, scaleSequentialLog, scaleSequentialPow, scaleSequentialQuantile, scaleSequentialSqrt, scaleSequentialSymlog, scaleSqrt, scaleSymlog, scaleThreshold, scaleTime } from 'd3-scale';
1
+ import { scaleBand, scaleDiverging, scaleDivergingLog, scaleDivergingPow, scaleDivergingSqrt, scaleDivergingSymlog, scaleLinear, scaleLog, scaleOrdinal, scalePoint, scalePow, scaleQuantile, scaleQuantize, scaleSequential, scaleSequentialLog, scaleSequentialPow, scaleSequentialQuantile, scaleSequentialSqrt, scaleSequentialSymlog, scaleSqrt, scaleSymlog, scaleThreshold, scaleTime, scaleUtc } from 'd3-scale';
2
2
  import { range as d3Range } from 'd3-array';
3
3
  import { categoricalSchemes, isCategoricalScheme, isDivergingScheme, isOrdinalScheme, isQuantitativeScheme, ordinalScheme, quantitativeScheme } from './colors.js';
4
4
  import callWithProps from './callWithProps.js';
@@ -6,11 +6,13 @@ import { interpolateLab, interpolateRound } from 'd3-interpolate';
6
6
  import { coalesce, maybeNumber } from './index.js';
7
7
  import { getLogTicks } from './getLogTicks.js';
8
8
  import { isPlainObject } from 'es-toolkit';
9
+ import { isTemporalScale } from './typeChecks.js';
9
10
  const Scales = {
10
11
  point: scalePoint,
11
12
  band: scaleBand,
12
13
  linear: scaleLinear,
13
14
  time: scaleTime,
15
+ utc: scaleUtc,
14
16
  sqrt: scaleSqrt,
15
17
  pow: scalePow,
16
18
  log: scaleLog,
@@ -55,7 +57,7 @@ export function autoScale({ name, type, domain, scaleOptions, plotOptions, plotW
55
57
  const scaleProps = {
56
58
  domain,
57
59
  range,
58
- ...((type === 'linear' || type === 'log' || type === 'time') && scaleOptions.nice
60
+ ...((type === 'linear' || type === 'log' || isTemporalScale(type)) && scaleOptions.nice
59
61
  ? {
60
62
  nice: scaleOptions.nice ? niceTickCount : true
61
63
  }
@@ -1,6 +1,6 @@
1
- import { maybeTimeInterval } from './time.js';
1
+ import { maybeTimeInterval, maybeUtcInterval } from './time.js';
2
2
  import { extent, range as rangei } from 'd3-array';
3
- export function maybeInterval(interval) {
3
+ export function maybeInterval(interval, scaleType) {
4
4
  if (interval == null)
5
5
  return;
6
6
  if (typeof interval === 'number') {
@@ -22,7 +22,7 @@ export function maybeInterval(interval) {
22
22
  };
23
23
  }
24
24
  if (typeof interval === 'string')
25
- return maybeTimeInterval(interval);
25
+ return scaleType === 'utc' ? maybeUtcInterval(interval) : maybeTimeInterval(interval);
26
26
  if (typeof interval.floor !== 'function')
27
27
  throw new Error('invalid interval; missing floor method');
28
28
  if (typeof interval.offset !== 'function')
@@ -36,7 +36,7 @@ export function autoTicks(type, ticks, interval, domain, scaleFn, count) {
36
36
  const [lo, hi] = extent(domain);
37
37
  if (lo == null || hi == null)
38
38
  return [];
39
- const I = maybeInterval(interval);
39
+ const I = maybeInterval(interval, type);
40
40
  if (!I)
41
41
  return [];
42
42
  return I.range(lo, I.offset(hi)).filter((d) => d >= lo && d <= hi);
@@ -5,33 +5,43 @@ const DATE_TIME = {
5
5
  month: 'short',
6
6
  day: 'numeric'
7
7
  };
8
- const autoFormatDateTime = (locale) => {
9
- const format = new Intl.DateTimeFormat(locale, DATE_TIME).format;
10
- return (date) => format(date).replace(', ', '\n');
8
+ const autoFormatDateTime = (locale, utc) => {
9
+ const formatter = new Intl.DateTimeFormat(locale, {
10
+ ...DATE_TIME,
11
+ ...(utc ? { timeZone: 'UTC' } : {})
12
+ });
13
+ return (date) => formatter.format(date).replace(', ', '\n');
11
14
  };
12
15
  const DAY_MONTH = {
13
16
  month: 'short',
14
17
  day: 'numeric'
15
18
  };
16
- const autoFormatDayMonth = (locale) => {
17
- const format = new Intl.DateTimeFormat(locale, DAY_MONTH).format;
18
- return (date) => format(date).replace(' ', '\n');
19
+ const autoFormatDayMonth = (locale, utc) => {
20
+ const formatter = new Intl.DateTimeFormat(locale, {
21
+ ...DAY_MONTH,
22
+ ...(utc ? { timeZone: 'UTC' } : {})
23
+ });
24
+ return (date) => formatter.format(date).replace(' ', '\n');
19
25
  };
20
26
  const MONTH_YEAR = {
21
27
  month: 'short',
22
28
  year: 'numeric'
23
29
  };
24
- const autoFormatMonthYear = (locale) => {
25
- const format = new Intl.DateTimeFormat(locale, MONTH_YEAR).format;
26
- return (date) => format(date).replace(' ', '\n');
30
+ const autoFormatMonthYear = (locale, utc) => {
31
+ const formatter = new Intl.DateTimeFormat(locale, {
32
+ ...MONTH_YEAR,
33
+ ...(utc ? { timeZone: 'UTC' } : {})
34
+ });
35
+ return (date) => formatter.format(date).replace(' ', '\n');
27
36
  };
28
37
  export default function autoTimeFormat(x, plotWidth, plotLocale) {
38
+ const utc = x.type === 'utc';
29
39
  const daysPer100Px = ((toNumber(x.domain[1]) - toNumber(x.domain[0])) / plotWidth / 864e5) * 100;
30
40
  const format = daysPer100Px < 1
31
- ? autoFormatDateTime(plotLocale)
41
+ ? autoFormatDateTime(plotLocale, utc)
32
42
  : daysPer100Px < 30
33
- ? autoFormatDayMonth(plotLocale)
34
- : autoFormatMonthYear(plotLocale);
43
+ ? autoFormatDayMonth(plotLocale, utc)
44
+ : autoFormatMonthYear(plotLocale, utc);
35
45
  return (date) => format(date).split('\n');
36
46
  }
37
47
  function toNumber(d) {
@@ -1,7 +1,7 @@
1
1
  import { extent, ascending } from 'd3-array';
2
2
  import { isColorOrNull, isDate, isDateOrNull, isNumberOrNull, isNumberOrNullOrNaN, isStringOrNull } from './typeChecks.js';
3
3
  import { CHANNEL_SCALE, ORIGINAL_NAME_KEYS, VALID_SCALE_TYPES } from '../constants.js';
4
- import { isSymbolOrNull } from './typeChecks.js';
4
+ import { isSymbolOrNull, isTemporalScale } from './typeChecks.js';
5
5
  import { resolveProp, toChannelOption } from './resolve.js';
6
6
  import isDataRecord from './isDataRecord.js';
7
7
  import { createProjection } from './projection.js';
@@ -165,7 +165,8 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
165
165
  sortOrdinalDomain = false;
166
166
  }
167
167
  // construct domain from data values
168
- const valueArr = [...dataValues.values(), ...(scaleOptions.domain || [])].filter((d) => d != null);
168
+ // For facet scales (fx/fy), null is a valid grouping category (e.g. penguins with sex=null)
169
+ const valueArr = [...dataValues.values(), ...(scaleOptions.domain || [])].filter((d) => d != null || name === 'fx' || name === 'fy');
169
170
  const type = !scaleOptions.type || scaleOptions.type === 'auto'
170
171
  ? inferScaleType(name, valueArr, markTypes, scaleOptions)
171
172
  : scaleOptions.type;
@@ -177,7 +178,9 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
177
178
  if (isOrdinal && sortOrdinalDomain) {
178
179
  valueArr.sort(ascending);
179
180
  }
180
- const valueArray = type === 'quantile' || type === 'quantile-cont' ? allDataValues.toSorted() : valueArr;
181
+ const valueArray = type === 'quantile' || type === 'quantile-cont'
182
+ ? allDataValues.toSorted((a, b) => Number(a) - Number(b))
183
+ : valueArr;
181
184
  let domain = scaleOptions.domain
182
185
  ? isOrdinal
183
186
  ? scaleOptions.domain
@@ -228,7 +231,7 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
228
231
  skip,
229
232
  manualActiveMarks,
230
233
  uniqueScaleProps,
231
- autoTitle: type === 'time'
234
+ autoTitle: isTemporalScale(type)
232
235
  ? null
233
236
  : propNames.size === 1
234
237
  ? `${[...propNames.values()][0]}${type === 'log' ? ' (log)' : ''}`
@@ -139,7 +139,7 @@ const timeFormatIntervals = [
139
139
  // from largest to smallest, used to determine the most specific standard time
140
140
  // format for a given array of dates. This is a subset of the tick intervals
141
141
  // listed above; we only need the breakpoints where the format changes.
142
- const formatIntervals = [
142
+ const _formatIntervals = [
143
143
  utcFormatIntervals[0],
144
144
  timeFormatIntervals[0],
145
145
  utcFormatIntervals[1],
@@ -8,3 +8,4 @@ export declare function isStringOrNull(v: RawValue | null | undefined): v is str
8
8
  export declare function isSymbolOrNull(v: RawValue | null | undefined): v is ("square" | "circle" | "asterisk" | "cross" | "diamond" | "diamond2" | "hexagon" | "plus" | "square2" | "star" | "times" | "triangle" | "triangle2" | "wye") | import("d3-shape").SymbolType | null | undefined;
9
9
  export declare function isColorOrNull(v: RawValue | null | undefined): boolean;
10
10
  export declare function isOpacityOrNull(v: RawValue): boolean;
11
+ export declare function isTemporalScale(type: string): boolean;
@@ -44,3 +44,6 @@ export function isColorOrNull(v) {
44
44
  export function isOpacityOrNull(v) {
45
45
  return v == null || (typeof v === 'number' && Number.isFinite(v) && v >= 0 && v <= 1);
46
46
  }
47
+ export function isTemporalScale(type) {
48
+ return type === 'time' || type === 'utc';
49
+ }
@@ -18,6 +18,7 @@
18
18
  import type * as CSS from 'csstype';
19
19
  import autoTimeFormat from '../helpers/autoTimeFormat.js';
20
20
  import { autoTicks } from '../helpers/autoTicks.js';
21
+ import { isTemporalScale } from '../helpers/typeChecks.js';
21
22
  import { resolveScaledStyles } from '../helpers/resolve.js';
22
23
  import { getPlotDefaults } from '../hooks/plotDefaults.js';
23
24
  import { extent } from 'd3-array';
@@ -161,10 +162,14 @@
161
162
  ? tickFmt
162
163
  : plot.scales.x.type === 'band' || plot.scales.x.type === 'point'
163
164
  ? (d: RawValue) => String(d)
164
- : plot.scales.x.type === 'time'
165
- ? // time scale
165
+ : isTemporalScale(plot.scales.x.type)
166
+ ? // time/utc scale
166
167
  typeof tickFmt === 'object'
167
- ? (d: Date) => Intl.DateTimeFormat(plot.options.locale, tickFmt).format(d)
168
+ ? (d: Date) =>
169
+ Intl.DateTimeFormat(plot.options.locale, {
170
+ ...tickFmt,
171
+ ...(plot.scales.x.type === 'utc' ? { timeZone: 'UTC' } : {})
172
+ }).format(d)
168
173
  : autoTimeFormat(plot.scales.x, plot.plotWidth, plot.options.locale)
169
174
  : // numeric scale
170
175
  typeof tickFmt === 'object'
@@ -17,6 +17,7 @@
17
17
  } from '../types/index.js';
18
18
  import autoTimeFormat from '../helpers/autoTimeFormat.js';
19
19
  import { autoTicks } from '../helpers/autoTicks.js';
20
+ import { isTemporalScale } from '../helpers/typeChecks.js';
20
21
  import { resolveScaledStyles } from '../helpers/resolve.js';
21
22
  import { getPlotDefaults } from '../hooks/plotDefaults.js';
22
23
  import { extent } from 'd3-array';
@@ -158,10 +159,14 @@
158
159
  ? tickFmt
159
160
  : plot.scales.y.type === 'band' || plot.scales.y.type === 'point'
160
161
  ? (d: RawValue) => String(d)
161
- : plot.scales.y.type === 'time'
162
- ? // time scale
162
+ : isTemporalScale(plot.scales.y.type)
163
+ ? // time/utc scale
163
164
  typeof tickFmt === 'object'
164
- ? (d: Date) => Intl.DateTimeFormat(plot.options.locale, tickFmt).format(d)
165
+ ? (d: Date) =>
166
+ Intl.DateTimeFormat(plot.options.locale, {
167
+ ...tickFmt,
168
+ ...(plot.scales.y.type === 'utc' ? { timeZone: 'UTC' } : {})
169
+ }).format(d)
165
170
  : autoTimeFormat(plot.scales.y, plot.plotWidth, plot.options.locale)
166
171
  : // numeric scale
167
172
  typeof tickFmt === 'object'
@@ -43,6 +43,7 @@
43
43
  regressionLoess
44
44
  } from '../../regression/index.js';
45
45
  import { resolveChannel } from '../../helpers/resolve.js';
46
+ import { isTemporalScale } from '../../helpers/typeChecks.js';
46
47
  import { confidenceInterval } from '../../helpers/math.js';
47
48
  import callWithProps from '../../helpers/callWithProps.js';
48
49
  import type { DataRecord, FacetContext, RawValue } from '../../types/index.js';
@@ -93,7 +94,7 @@
93
94
 
94
95
  // Convert generated points back to Date for time scales so downstream marks render correctly.
95
96
  function toOutputX(value: number, scaleType: string): RawValue {
96
- return scaleType === 'time' ? new Date(value) : value;
97
+ return isTemporalScale(scaleType) ? new Date(value) : value;
97
98
  }
98
99
 
99
100
  function makeTicks(domain: [number, number], count = 40): number[] {
@@ -84,7 +84,7 @@ export type PlotDefaults = {
84
84
  * default color scheme
85
85
  */
86
86
  colorScheme: ColorScheme;
87
- categoricalColorScheme: ColorScheme | string[];
87
+ categoricalColorScheme: ColorScheme | string[] | Record<string, string>;
88
88
  /**
89
89
  * fallback color to be used for null/NA
90
90
  */
@@ -126,7 +126,7 @@ export type ColorScaleOptions = ScaleOptions & {
126
126
  /**
127
127
  * the name of the color scheme to use, e.g. 'blues', 'turbo', 'rdylbu'
128
128
  */
129
- scheme: ColorScheme | string[];
129
+ scheme: ColorScheme | string[] | Record<string, string>;
130
130
  /**
131
131
  * fallback color used for null/undefined
132
132
  */
@@ -148,7 +148,7 @@ export type ColorScaleOptions = ScaleOptions & {
148
148
  */
149
149
  tickFormat: false | Intl.NumberFormatOptions | TickFormatFunction;
150
150
  };
151
- export type ScaleType = 'linear' | 'pow' | 'sqrt' | 'log' | 'symlog' | 'time' | 'point' | 'ordinal' | 'sequential' | 'band' | 'categorical' | 'cyclical' | 'threshold' | 'quantile-cont' | 'quantile' | 'quantize' | 'diverging' | 'diverging-log' | 'diverging-pow' | 'diverging-sqrt' | 'diverging-symlog';
151
+ export type ScaleType = 'linear' | 'pow' | 'sqrt' | 'log' | 'symlog' | 'time' | 'utc' | 'point' | 'ordinal' | 'sequential' | 'band' | 'categorical' | 'cyclical' | 'threshold' | 'quantile-cont' | 'quantile' | 'quantize' | 'diverging' | 'diverging-log' | 'diverging-pow' | 'diverging-sqrt' | 'diverging-symlog';
152
152
  export type XScaleOptions = ScaleOptions & {
153
153
  /**
154
154
  * Activate the implicit GridX mark. For more control over the grid styling
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelteplot",
3
- "version": "0.11.0-pr-514.0",
3
+ "version": "0.11.1",
4
4
  "description": "A Svelte-native data visualization framework based on the layered grammar of graphics principles.",
5
5
  "keywords": [
6
6
  "svelte",
@@ -105,7 +105,7 @@
105
105
  "@sveltejs/adapter-static": "^3.0.10",
106
106
  "@sveltejs/enhanced-img": "^0.10.2",
107
107
  "@sveltejs/eslint-config": "^8.3.5",
108
- "@sveltejs/kit": "^2.53.4",
108
+ "@sveltejs/kit": "^2.52.2",
109
109
  "@sveltejs/package": "^2.5.7",
110
110
  "@sveltejs/vite-plugin-svelte": "6.2.4",
111
111
  "@sveltepress/twoslash": "^1.3.6",
@@ -126,9 +126,9 @@
126
126
  "@types/geojson": "^7946.0.16",
127
127
  "@types/topojson": "^3.2.6",
128
128
  "@types/topojson-client": "^3.1.5",
129
- "@typescript-eslint/eslint-plugin": "^8.56.1",
130
- "@typescript-eslint/parser": "^8.56.1",
131
- "@unocss/extractor-svelte": "^66.6.3",
129
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
130
+ "@typescript-eslint/parser": "^8.56.0",
131
+ "@unocss/extractor-svelte": "^66.6.0",
132
132
  "@vite-pwa/sveltekit": "^1.1.0",
133
133
  "csstype": "^3.2.3",
134
134
  "d3-dsv": "^3.0.1",
@@ -144,7 +144,7 @@
144
144
  "log-update": "^7.1.0",
145
145
  "lru-cache": "^11.2.6",
146
146
  "magic-string": "^0.30.21",
147
- "mdast-util-from-markdown": "^2.0.3",
147
+ "mdast-util-from-markdown": "^2.0.2",
148
148
  "mdast-util-gfm": "^3.1.0",
149
149
  "oxlint": "^1.48.0",
150
150
  "oxlint-tsgolint": "^0.14.0",
@@ -152,16 +152,16 @@
152
152
  "pngjs": "^7.0.0",
153
153
  "prettier": "^3.8.1",
154
154
  "prettier-plugin-svelte": "^3.5.0",
155
- "puppeteer": "^24.37.5",
155
+ "puppeteer": "^24.37.4",
156
156
  "remark-code-extra": "^1.0.1",
157
157
  "remark-code-frontmatter": "^1.0.0",
158
158
  "remark-math": "^6.0.0",
159
159
  "resize-observer-polyfill": "^1.5.1",
160
160
  "sass": "^1.97.3",
161
161
  "shiki": "^3.22.0",
162
- "svelte": "^5.53.5",
162
+ "svelte": "5",
163
163
  "svelte-check": "^4.4.1",
164
- "svelte-eslint-parser": "1.5.1",
164
+ "svelte-eslint-parser": "1.4.1",
165
165
  "svelte-highlight": "^7.9.0",
166
166
  "svg-path-parser": "^1.1.0",
167
167
  "temml": "^0.13.1",
@@ -173,7 +173,7 @@
173
173
  "typescript": "^5.9.3",
174
174
  "uid": "^2.0.2",
175
175
  "unist-util-visit": "^5.1.0",
176
- "unocss": "^66.6.2",
176
+ "unocss": "^66.6.0",
177
177
  "vite": "^7.3.1",
178
178
  "vitest": "^4.0.18",
179
179
  "vitest-matchmedia-mock": "^2.0.3",
@@ -181,7 +181,7 @@
181
181
  "yoctocolors": "^2.1.2"
182
182
  },
183
183
  "peerDependencies": {
184
- "svelte": "^5.53.5"
184
+ "svelte": "^5.43.0"
185
185
  },
186
- "packageManager": "pnpm@10.30.3"
186
+ "packageManager": "pnpm@10.30.0"
187
187
  }