@qtsurfer/sveltecharts 0.6.0 → 0.8.0
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/LightweightTimeSeriesChartBuilder.d.ts +7 -1
- package/dist/LightweightTimeSeriesChartBuilder.d.ts.map +1 -1
- package/dist/LightweightTimeSeriesChartBuilder.js +86 -2
- package/dist/SVELightweightCharts.svelte +2 -1
- package/dist/SVELightweightCharts.svelte.d.ts.map +1 -1
- package/dist/TimeSeriesChartBuilder.d.ts +16 -1
- package/dist/TimeSeriesChartBuilder.d.ts.map +1 -1
- package/dist/TimeSeriesChartBuilder.js +66 -0
- package/dist/chartAdapter.d.ts +7 -0
- package/dist/chartAdapter.d.ts.map +1 -1
- package/dist/mockDataSet.d.ts +7 -0
- package/dist/mockDataSet.d.ts.map +1 -1
- package/dist/mockDataSet.js +22 -0
- package/package.json +1 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type IChartApi } from 'lightweight-charts';
|
|
2
|
-
import type { ChartDataset, ChartDatasetFormatSimpleObject, ChartMarkerPointOptions, TimeSeriesChartAdapter } from './chartAdapter';
|
|
2
|
+
import type { ChartDataset, ChartDatasetFormatSimpleObject, ChartMarkerPointOptions, OHLCDimensions, TimeSeriesChartAdapter } from './chartAdapter';
|
|
3
3
|
type ConfigBuilder = {
|
|
4
4
|
externalManagerLegend?: boolean;
|
|
5
5
|
};
|
|
6
|
+
export declare function getPricePrecision(values: number[]): number;
|
|
7
|
+
export declare function formatPreciseValue(value: number): string;
|
|
6
8
|
export declare class LightweightTimeSeriesChartBuilder implements TimeSeriesChartAdapter {
|
|
7
9
|
LightweightChart: IChartApi;
|
|
8
10
|
private builderConfig;
|
|
@@ -12,6 +14,8 @@ export declare class LightweightTimeSeriesChartBuilder implements TimeSeriesChar
|
|
|
12
14
|
private _tsColumn;
|
|
13
15
|
private selected;
|
|
14
16
|
private series;
|
|
17
|
+
private _candlestickSeries;
|
|
18
|
+
private _ohlcDims;
|
|
15
19
|
private markersPlugins;
|
|
16
20
|
private markers;
|
|
17
21
|
private _dataDirty;
|
|
@@ -20,6 +24,7 @@ export declare class LightweightTimeSeriesChartBuilder implements TimeSeriesChar
|
|
|
20
24
|
constructor(instance: IChartApi, builderConfig?: ConfigBuilder);
|
|
21
25
|
setLegendIcon(_icon: string): this;
|
|
22
26
|
setDataset(data: ChartDataset, yDimensionsNames?: string[]): this;
|
|
27
|
+
setCandlestickSeries(data: ChartDatasetFormatSimpleObject, dims: OHLCDimensions): this;
|
|
23
28
|
addDimension(data: ChartDatasetFormatSimpleObject, dimName: string): this;
|
|
24
29
|
addMarkerPoint(id: number, data: {
|
|
25
30
|
dimName: string;
|
|
@@ -44,6 +49,7 @@ export declare class LightweightTimeSeriesChartBuilder implements TimeSeriesChar
|
|
|
44
49
|
private syncSeriesMarkers;
|
|
45
50
|
private expandTimeRangeForMarkers;
|
|
46
51
|
private clearSeries;
|
|
52
|
+
private toCandlestickData;
|
|
47
53
|
private toLineData;
|
|
48
54
|
private toChartTime;
|
|
49
55
|
private forceTimeRangeToDataset;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LightweightTimeSeriesChartBuilder.d.ts","sourceRoot":"","sources":["../src/lib/LightweightTimeSeriesChartBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"LightweightTimeSeriesChartBuilder.d.ts","sourceRoot":"","sources":["../src/lib/LightweightTimeSeriesChartBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,KAAK,SAAS,EAUd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACX,YAAY,EAGZ,8BAA8B,EAC9B,uBAAuB,EACvB,cAAc,EACd,sBAAsB,EACtB,MAAM,gBAAgB,CAAC;AAExB,KAAK,aAAa,GAAG;IACpB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AA6BF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAWjD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,UAW/C;AAED,qBAAa,iCAAkC,YAAW,sBAAsB;IACxE,gBAAgB,EAAE,SAAS,CAAC;IACnC,OAAO,CAAC,aAAa,CAEnB;IACF,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,MAAM,CAA+C;IAC7D,OAAO,CAAC,kBAAkB,CAAgD;IAC1E,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,cAAc,CAAoD;IAC1E,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAS;gBAErB,QAAQ,EAAE,SAAS,EAAE,aAAa,CAAC,EAAE,aAAa;IAK9D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAejE,oBAAoB,CAAC,IAAI,EAAE,8BAA8B,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI;IA4BtF,YAAY,CAAC,IAAI,EAAE,8BAA8B,EAAE,OAAO,EAAE,MAAM;IAclE,cAAc,CACb,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACd,EACD,OAAO,CAAC,EAAE,uBAAuB,GAC/B,IAAI;IAmBP,KAAK;IAqCL,eAAe;IAIf,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAWlC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAuB1C,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAqBrC,YAAY;IAIZ,cAAc,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IAQlC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAmBxD,YAAY,IAAI,IAAI;IAQpB,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,qBAAqB;IAqB7B,OAAO,CAAC,oBAAoB;IA2B5B,OAAO,CAAC,eAAe;IAsCvB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,iBAAiB;IAoCzB,OAAO,CAAC,yBAAyB;IA4BjC,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,uBAAuB;IA4B/B,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,iBAAiB;CAWzB"}
|
|
@@ -1,5 +1,36 @@
|
|
|
1
|
-
import { LineSeries, createSeriesMarkers } from 'lightweight-charts';
|
|
1
|
+
import { LineSeries, CandlestickSeries, createSeriesMarkers } from 'lightweight-charts';
|
|
2
2
|
const SERIES_COLORS = ['#2563eb', '#16a34a', '#dc2626', '#7c3aed', '#d97706', '#0891b2'];
|
|
3
|
+
const DEFAULT_PRICE_PRECISION = 2;
|
|
4
|
+
const MAX_PRICE_PRECISION = 12;
|
|
5
|
+
function getDecimalPrecision(value) {
|
|
6
|
+
if (!Number.isFinite(value) || value === 0) {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
const [mantissa, exponentValue] = Math.abs(value).toExponential(MAX_PRICE_PRECISION).split('e');
|
|
10
|
+
const exponent = Number(exponentValue);
|
|
11
|
+
const significantDecimals = (mantissa.split('.')[1] ?? '').replace(/0+$/, '').length;
|
|
12
|
+
return Math.max(0, Math.min(MAX_PRICE_PRECISION, significantDecimals - exponent));
|
|
13
|
+
}
|
|
14
|
+
export function getPricePrecision(values) {
|
|
15
|
+
let precision = DEFAULT_PRICE_PRECISION;
|
|
16
|
+
for (const value of values) {
|
|
17
|
+
precision = Math.max(precision, getDecimalPrecision(value));
|
|
18
|
+
if (precision >= MAX_PRICE_PRECISION) {
|
|
19
|
+
return MAX_PRICE_PRECISION;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return precision;
|
|
23
|
+
}
|
|
24
|
+
export function formatPreciseValue(value) {
|
|
25
|
+
if (!Number.isFinite(value)) {
|
|
26
|
+
return String(value);
|
|
27
|
+
}
|
|
28
|
+
const precision = getDecimalPrecision(value);
|
|
29
|
+
if (precision === 0) {
|
|
30
|
+
return value.toString();
|
|
31
|
+
}
|
|
32
|
+
return value.toFixed(precision).replace(/\.?0+$/, '');
|
|
33
|
+
}
|
|
3
34
|
export class LightweightTimeSeriesChartBuilder {
|
|
4
35
|
LightweightChart;
|
|
5
36
|
builderConfig = {
|
|
@@ -11,6 +42,8 @@ export class LightweightTimeSeriesChartBuilder {
|
|
|
11
42
|
_tsColumn = '_ts';
|
|
12
43
|
selected = {};
|
|
13
44
|
series = new Map();
|
|
45
|
+
_candlestickSeries = null;
|
|
46
|
+
_ohlcDims = null;
|
|
14
47
|
markersPlugins = new Map();
|
|
15
48
|
markers = new Map();
|
|
16
49
|
_dataDirty = false;
|
|
@@ -35,6 +68,28 @@ export class LightweightTimeSeriesChartBuilder {
|
|
|
35
68
|
this.createSeriesData();
|
|
36
69
|
return this.build();
|
|
37
70
|
}
|
|
71
|
+
setCandlestickSeries(data, dims) {
|
|
72
|
+
this._tsColumn = Object.keys(data)[0];
|
|
73
|
+
this.dataset = data;
|
|
74
|
+
this._ohlcDims = dims;
|
|
75
|
+
// Remove existing candlestick series before recreating
|
|
76
|
+
if (this._candlestickSeries) {
|
|
77
|
+
this.LightweightChart.removeSeries(this._candlestickSeries);
|
|
78
|
+
this._candlestickSeries = null;
|
|
79
|
+
}
|
|
80
|
+
this._candlestickSeries = this.LightweightChart.addSeries(CandlestickSeries, {
|
|
81
|
+
upColor: '#26a69a',
|
|
82
|
+
downColor: '#ef5350',
|
|
83
|
+
borderVisible: false,
|
|
84
|
+
wickUpColor: '#26a69a',
|
|
85
|
+
wickDownColor: '#ef5350'
|
|
86
|
+
});
|
|
87
|
+
this.selected['Candlestick'] = true;
|
|
88
|
+
const candleData = this.toCandlestickData(dims);
|
|
89
|
+
this._candlestickSeries.setData(candleData);
|
|
90
|
+
this.LightweightChart.timeScale().fitContent();
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
38
93
|
addDimension(data, dimName) {
|
|
39
94
|
if (!this.dataset[this._tsColumn]?.length) {
|
|
40
95
|
throw new Error('No source data or dimensions found. Before loading data');
|
|
@@ -264,6 +319,7 @@ export class LightweightTimeSeriesChartBuilder {
|
|
|
264
319
|
});
|
|
265
320
|
}
|
|
266
321
|
addSeries(dim, dimName, isSelected, index) {
|
|
322
|
+
const pricePrecision = getPricePrecision(this.dataset[dim] ?? []);
|
|
267
323
|
const series = this.LightweightChart.addSeries(LineSeries, {
|
|
268
324
|
color: SERIES_COLORS[(index ?? this.series.size) % SERIES_COLORS.length],
|
|
269
325
|
lineWidth: 1,
|
|
@@ -271,7 +327,12 @@ export class LightweightTimeSeriesChartBuilder {
|
|
|
271
327
|
priceScaleId: this.isPercentageDimension(dim) ? 'left' : 'right',
|
|
272
328
|
visible: isSelected,
|
|
273
329
|
crosshairMarkerVisible: false,
|
|
274
|
-
lastValueVisible: true
|
|
330
|
+
lastValueVisible: true,
|
|
331
|
+
priceFormat: {
|
|
332
|
+
type: 'price',
|
|
333
|
+
precision: pricePrecision,
|
|
334
|
+
minMove: 10 ** -pricePrecision
|
|
335
|
+
}
|
|
275
336
|
});
|
|
276
337
|
this.series.set(dim, series);
|
|
277
338
|
this.selected[dim] = isSelected;
|
|
@@ -340,12 +401,35 @@ export class LightweightTimeSeriesChartBuilder {
|
|
|
340
401
|
for (const series of this.series.values()) {
|
|
341
402
|
this.LightweightChart.removeSeries(series);
|
|
342
403
|
}
|
|
404
|
+
if (this._candlestickSeries) {
|
|
405
|
+
this.LightweightChart.removeSeries(this._candlestickSeries);
|
|
406
|
+
this._candlestickSeries = null;
|
|
407
|
+
this._ohlcDims = null;
|
|
408
|
+
}
|
|
343
409
|
this.series.clear();
|
|
344
410
|
this.markersPlugins.clear();
|
|
345
411
|
this.markers.clear();
|
|
346
412
|
this._timeRangeForced = false;
|
|
347
413
|
this._building = false;
|
|
348
414
|
}
|
|
415
|
+
toCandlestickData(dims) {
|
|
416
|
+
const timestamps = this.dataset[this._tsColumn] ?? [];
|
|
417
|
+
const opens = this.dataset[dims.open] ?? [];
|
|
418
|
+
const highs = this.dataset[dims.high] ?? [];
|
|
419
|
+
const lows = this.dataset[dims.low] ?? [];
|
|
420
|
+
const closes = this.dataset[dims.close] ?? [];
|
|
421
|
+
const seen = new Set();
|
|
422
|
+
const result = [];
|
|
423
|
+
for (let i = 0; i < timestamps.length; i++) {
|
|
424
|
+
const t = this.toChartTime(timestamps[i]);
|
|
425
|
+
const tNum = t;
|
|
426
|
+
if (seen.has(tNum))
|
|
427
|
+
continue;
|
|
428
|
+
seen.add(tNum);
|
|
429
|
+
result.push({ time: t, open: opens[i], high: highs[i], low: lows[i], close: closes[i] });
|
|
430
|
+
}
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
349
433
|
toLineData(dim) {
|
|
350
434
|
const timestamps = this.dataset[this._tsColumn] ?? [];
|
|
351
435
|
const values = this.dataset[dim] ?? [];
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
type MouseEventParams,
|
|
10
10
|
type Time
|
|
11
11
|
} from 'lightweight-charts';
|
|
12
|
+
import { formatPreciseValue } from './LightweightTimeSeriesChartBuilder';
|
|
12
13
|
|
|
13
14
|
type LightweightChartsConfig = {
|
|
14
15
|
options?: DeepPartial<ChartOptions>;
|
|
@@ -100,7 +101,7 @@
|
|
|
100
101
|
const value = data?.value;
|
|
101
102
|
if (value === undefined || value === null) continue;
|
|
102
103
|
const label = (series.options() as { title?: string }).title ?? '';
|
|
103
|
-
rows.push({ label, value: value
|
|
104
|
+
rows.push({ label, value: formatPreciseValue(value) });
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
if (rows.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SVELightweightCharts.svelte.d.ts","sourceRoot":"","sources":["../src/lib/SVELightweightCharts.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EAKd,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"SVELightweightCharts.svelte.d.ts","sourceRoot":"","sources":["../src/lib/SVELightweightCharts.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EAKd,MAAM,oBAAoB,CAAC;AAI5B,KAAK,uBAAuB,GAAG;IAC9B,OAAO,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CACpC,CAAC;AAGF,KAAK,gBAAgB,GAAI;IACxB,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AA+KH,QAAA,MAAM,oBAAoB,yEAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type LineSeriesOption, type DataZoomComponentOption } from 'echarts';
|
|
2
2
|
import { type ECharts } from './';
|
|
3
|
-
import type { ChartMarkerPointOptions } from './chartAdapter';
|
|
3
|
+
import type { ChartDatasetFormatSimpleObject, ChartMarkerPointOptions, OHLCDimensions } from './chartAdapter';
|
|
4
4
|
import type { GridOption } from 'echarts/types/dist/shared';
|
|
5
5
|
import type { ZRColor } from 'echarts/types/src/util/types.js';
|
|
6
6
|
type IconType = 'circle' | 'rect' | 'roundRect' | 'triangle' | 'diamond' | 'pin' | 'arrowUp' | 'arrowDown' | 'none';
|
|
@@ -35,12 +35,27 @@ export declare class TimeSeriesChartBuilder {
|
|
|
35
35
|
private yDimensions;
|
|
36
36
|
private yDimensionNames?;
|
|
37
37
|
private _tsColumn;
|
|
38
|
+
private _ohlcDims;
|
|
38
39
|
constructor(instance: ECharts, builderConfig?: ConfigBuilder);
|
|
39
40
|
/**
|
|
40
41
|
* Accepts data as rows: [timestamp, v1, v2, ...]
|
|
41
42
|
* Automatically generates line series for each value column (>=1).
|
|
42
43
|
*/
|
|
43
44
|
setDataset(data: DatasetFormatArray | DatasetFormatObject | DatasetFormatSimpleObject, yDimensionsNames?: string[]): this;
|
|
45
|
+
/**
|
|
46
|
+
* Loads OHLC data and renders a candlestick series.
|
|
47
|
+
* data must be a columnar object: { _ts: number[], open: number[], high: number[], low: number[], close: number[] }
|
|
48
|
+
* dims specifies the column names for each OHLC role.
|
|
49
|
+
*
|
|
50
|
+
* Calling this method multiple times replaces any existing candlestick series in place.
|
|
51
|
+
*/
|
|
52
|
+
setCandlestickSeries(data: ChartDatasetFormatSimpleObject, dims: OHLCDimensions): this;
|
|
53
|
+
/**
|
|
54
|
+
* Removes the candlestick series (if any) and clears OHLC state.
|
|
55
|
+
* Useful before switching back to line rendering on the same builder instance.
|
|
56
|
+
*/
|
|
57
|
+
clearCandlestickSeries(): this;
|
|
58
|
+
private removeCandlestickSeries;
|
|
44
59
|
toggleLegend(column: string): this;
|
|
45
60
|
goToZoom(start: number, end: number): this;
|
|
46
61
|
scrollToTime(timestamp: number): this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeSeriesChartBuilder.d.ts","sourceRoot":"","sources":["../src/lib/TimeSeriesChartBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAE5B,MAAM,SAAS,CAAC;AACjB,OAAO,EAAsB,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"TimeSeriesChartBuilder.d.ts","sourceRoot":"","sources":["../src/lib/TimeSeriesChartBuilder.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {} from 'echarts';
|
|
2
2
|
import {} from './';
|
|
3
|
+
const CANDLESTICK_SERIES_ID = 'candlestick';
|
|
3
4
|
export class TimeSeriesChartBuilder {
|
|
4
5
|
ECharts;
|
|
5
6
|
builderConfig = {
|
|
@@ -9,6 +10,7 @@ export class TimeSeriesChartBuilder {
|
|
|
9
10
|
yDimensions;
|
|
10
11
|
yDimensionNames;
|
|
11
12
|
_tsColumn = '_ts';
|
|
13
|
+
_ohlcDims = null;
|
|
12
14
|
constructor(instance, builderConfig) {
|
|
13
15
|
this.ECharts = instance;
|
|
14
16
|
this.builderConfig = { ...this.builderConfig, ...builderConfig };
|
|
@@ -116,6 +118,70 @@ export class TimeSeriesChartBuilder {
|
|
|
116
118
|
}
|
|
117
119
|
return this.build();
|
|
118
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Loads OHLC data and renders a candlestick series.
|
|
123
|
+
* data must be a columnar object: { _ts: number[], open: number[], high: number[], low: number[], close: number[] }
|
|
124
|
+
* dims specifies the column names for each OHLC role.
|
|
125
|
+
*
|
|
126
|
+
* Calling this method multiple times replaces any existing candlestick series in place.
|
|
127
|
+
*/
|
|
128
|
+
setCandlestickSeries(data, dims) {
|
|
129
|
+
this._tsColumn = Object.keys(data)[0];
|
|
130
|
+
this.yDimensions = [dims.open, dims.high, dims.low, dims.close];
|
|
131
|
+
this.yDimensionNames = [dims.open, dims.high, dims.low, dims.close];
|
|
132
|
+
this._ohlcDims = dims;
|
|
133
|
+
if (this.option.dataset && !Array.isArray(this.option.dataset)) {
|
|
134
|
+
this.option.dataset.dimensions = [this._tsColumn, dims.open, dims.high, dims.low, dims.close];
|
|
135
|
+
this.option.dataset.source = data;
|
|
136
|
+
}
|
|
137
|
+
const selected = this.option.legend.selected;
|
|
138
|
+
Object.assign(selected, { Candlestick: true });
|
|
139
|
+
this.removeCandlestickSeries();
|
|
140
|
+
this.option.series.push({
|
|
141
|
+
type: 'candlestick',
|
|
142
|
+
id: CANDLESTICK_SERIES_ID,
|
|
143
|
+
name: 'Candlestick',
|
|
144
|
+
encode: {
|
|
145
|
+
x: this._tsColumn,
|
|
146
|
+
// ECharts candlestick encode order: [open, close, low, high]
|
|
147
|
+
y: [dims.open, dims.close, dims.low, dims.high]
|
|
148
|
+
},
|
|
149
|
+
animation: false,
|
|
150
|
+
progressive: 4000,
|
|
151
|
+
progressiveThreshold: 3000,
|
|
152
|
+
itemStyle: {
|
|
153
|
+
color: '#26a69a',
|
|
154
|
+
color0: '#ef5350',
|
|
155
|
+
borderColor: '#26a69a',
|
|
156
|
+
borderColor0: '#ef5350'
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
return this.build();
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Removes the candlestick series (if any) and clears OHLC state.
|
|
163
|
+
* Useful before switching back to line rendering on the same builder instance.
|
|
164
|
+
*/
|
|
165
|
+
clearCandlestickSeries() {
|
|
166
|
+
if (!this._ohlcDims)
|
|
167
|
+
return this;
|
|
168
|
+
this.removeCandlestickSeries();
|
|
169
|
+
this._ohlcDims = null;
|
|
170
|
+
const selected = this.option.legend.selected;
|
|
171
|
+
delete selected['Candlestick'];
|
|
172
|
+
// Force ECharts to drop the removed candlestick from its internal state.
|
|
173
|
+
this.ECharts.setOption(this.option, {
|
|
174
|
+
lazyUpdate: true,
|
|
175
|
+
notMerge: false,
|
|
176
|
+
replaceMerge: ['dataset', 'series']
|
|
177
|
+
});
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
removeCandlestickSeries() {
|
|
181
|
+
if (!Array.isArray(this.option.series))
|
|
182
|
+
return;
|
|
183
|
+
this.option.series = this.option.series.filter((s) => s.id !== CANDLESTICK_SERIES_ID);
|
|
184
|
+
}
|
|
119
185
|
toggleLegend(column) {
|
|
120
186
|
if (!column || !this.ECharts)
|
|
121
187
|
return this;
|
package/dist/chartAdapter.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export type ChartDatasetFormatSimpleObject = Record<string, number[]>;
|
|
2
2
|
export type ChartDatasetFormatObject = Record<string, any>[];
|
|
3
3
|
export type ChartDatasetFormatArray = number[][];
|
|
4
|
+
export type OHLCDimensions = {
|
|
5
|
+
open: string;
|
|
6
|
+
high: string;
|
|
7
|
+
low: string;
|
|
8
|
+
close: string;
|
|
9
|
+
};
|
|
4
10
|
export type ChartDataset = ChartDatasetFormatArray | ChartDatasetFormatObject | ChartDatasetFormatSimpleObject;
|
|
5
11
|
export type ChartMarkerPoint = {
|
|
6
12
|
dimName: string;
|
|
@@ -16,6 +22,7 @@ export type ChartMarkerPointOptions = {
|
|
|
16
22
|
export interface TimeSeriesChartAdapter {
|
|
17
23
|
setLegendIcon(icon: string): this;
|
|
18
24
|
setDataset(data: ChartDataset, yDimensionsNames?: string[]): this;
|
|
25
|
+
setCandlestickSeries(data: ChartDatasetFormatSimpleObject, dims: OHLCDimensions): this;
|
|
19
26
|
build(): this;
|
|
20
27
|
addDimension(data: ChartDatasetFormatSimpleObject, dimName: string): this;
|
|
21
28
|
addMarkerPoint(id: number, data: ChartMarkerPoint, options?: ChartMarkerPointOptions): this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chartAdapter.d.ts","sourceRoot":"","sources":["../src/lib/chartAdapter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,8BAA8B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7D,MAAM,MAAM,uBAAuB,GAAG,MAAM,EAAE,EAAE,CAAC;AAEjD,MAAM,MAAM,YAAY,GACrB,uBAAuB,GACvB,wBAAwB,GACxB,8BAA8B,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACtC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClE,KAAK,IAAI,IAAI,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,8BAA8B,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC5F,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,cAAc,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,YAAY,IAAI,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,YAAY,IAAI,IAAI,CAAC;CACrB"}
|
|
1
|
+
{"version":3,"file":"chartAdapter.d.ts","sourceRoot":"","sources":["../src/lib/chartAdapter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,8BAA8B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AACtE,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7D,MAAM,MAAM,uBAAuB,GAAG,MAAM,EAAE,EAAE,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,YAAY,GACrB,uBAAuB,GACvB,wBAAwB,GACxB,8BAA8B,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACtC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClE,oBAAoB,CAAC,IAAI,EAAE,8BAA8B,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACvF,KAAK,IAAI,IAAI,CAAC;IACd,YAAY,CAAC,IAAI,EAAE,8BAA8B,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC5F,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,cAAc,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,YAAY,IAAI,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAChE,YAAY,IAAI,IAAI,CAAC;CACrB"}
|
package/dist/mockDataSet.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export declare function createOHLCDataSet(bars: number, intervalMs?: number): {
|
|
2
|
+
_ts: number[];
|
|
3
|
+
open: number[];
|
|
4
|
+
high: number[];
|
|
5
|
+
low: number[];
|
|
6
|
+
close: number[];
|
|
7
|
+
};
|
|
1
8
|
export declare function createDataSet<T>(hours: number, type: 'object' | 'array'): {
|
|
2
9
|
data: T[];
|
|
3
10
|
yDimensionsNames: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockDataSet.d.ts","sourceRoot":"","sources":["../src/lib/mockDataSet.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO;UA8BxD,CAAC,EAAE;;EAGlB"}
|
|
1
|
+
{"version":3,"file":"mockDataSet.d.ts","sourceRoot":"","sources":["../src/lib/mockDataSet.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAAS;;;;;;EA0BlE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO;UA8BxD,CAAC,EAAE;;EAGlB"}
|
package/dist/mockDataSet.js
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
export function createOHLCDataSet(bars, intervalMs = 60_000) {
|
|
2
|
+
let startDate = new Date(2025, 9, 28, 14, 0, 0).getTime();
|
|
3
|
+
let price = 100;
|
|
4
|
+
const ts = [];
|
|
5
|
+
const open = [];
|
|
6
|
+
const high = [];
|
|
7
|
+
const low = [];
|
|
8
|
+
const close = [];
|
|
9
|
+
for (let i = 0; i < bars; i++) {
|
|
10
|
+
const o = price + (Math.random() - 0.5) * 2;
|
|
11
|
+
const c = o + (Math.random() - 0.5) * 3;
|
|
12
|
+
const h = Math.max(o, c) + Math.random() * 1.5;
|
|
13
|
+
const l = Math.min(o, c) - Math.random() * 1.5;
|
|
14
|
+
ts.push(startDate + i * intervalMs);
|
|
15
|
+
open.push(parseFloat(o.toFixed(4)));
|
|
16
|
+
high.push(parseFloat(h.toFixed(4)));
|
|
17
|
+
low.push(parseFloat(l.toFixed(4)));
|
|
18
|
+
close.push(parseFloat(c.toFixed(4)));
|
|
19
|
+
price = c;
|
|
20
|
+
}
|
|
21
|
+
return { _ts: ts, open, high, low, close };
|
|
22
|
+
}
|
|
1
23
|
export function createDataSet(hours, type) {
|
|
2
24
|
// Create random number between min and max
|
|
3
25
|
const random = (min = 45, max = 50) => Math.random() * max + min;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@qtsurfer/sveltecharts",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "QTSurfer (https://github.com/QTSurfer)",
|
|
7
7
|
"homepage": "https://github.com/QTSurfer/svelte-timeseries/tree/main/packages/sveltecharts",
|