Skip to content

Commit 91eb928

Browse files
committed
New feature - VueUiCandlestick - Add optional zoom minimap
1 parent a0d0334 commit 91eb928

File tree

3 files changed

+655
-180
lines changed

3 files changed

+655
-180
lines changed

TestingArena/ArenaVueUiCandlestick.vue

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,45 @@ import { VueUiCandlestick as VueUiCandlestickTreshaken } from "vue-data-ui/vue-u
1111
1212
const dataset = ref([]);
1313
14+
function generateRandomCandlestickData({
15+
count = 12,
16+
startDate = Date.UTC(2024, 0, 1), // starting date (Jan 1, 2024)
17+
interval = 30 * 24 * 60 * 60 * 1000, // 1 month in ms
18+
startPrice = 100,
19+
volatility = 0.2 // 20% volatility
20+
} = {}) {
21+
const data = [];
22+
let lastClose = startPrice;
23+
24+
for (let i = 0; i < count; i++) {
25+
const timestamp = startDate + i * interval;
26+
27+
// simulate price movement
28+
const changePercent = (Math.random() - 0.5) * volatility;
29+
const open = lastClose;
30+
const close = open * (1 + changePercent);
31+
const high = Math.max(open, close) * (1 + Math.random() * volatility);
32+
const low = Math.min(open, close) * (1 - Math.random() * volatility);
33+
const volume = Math.round(1000 + Math.random() * 9000);
34+
35+
data.push([
36+
timestamp,
37+
Math.round(open),
38+
Math.round(high),
39+
Math.round(low),
40+
Math.round(close),
41+
volume
42+
]);
43+
44+
lastClose = close;
45+
}
46+
return data;
47+
}
48+
1449
onMounted(() => {
1550
dataset.value = undefined;
1651
setTimeout(() => {
17-
dataset.value = [
18-
[1704067200000, 10, 20, 2, 10, 30],
19-
[1706745600000, 10, 30, 5, 20, 50],
20-
[1709251200000, 20, 50, 10, 30, 80],
21-
[1711929600000, 30, 80, 20, 50, 130],
22-
[1714521600000, 50, 130, 30, 100, 210],
23-
[1717200000000, 80, 210, 50, 150, 340],
24-
[1719792000000, 130, 340, 80, 280, 550],
25-
[1722470400000, 210, 550, 130, 50, 890],
26-
[1725148800000, 340, 890, 210, 750, 1440],
27-
[1727740800000, 550, 1440, 340, 1230, 2330],
28-
[1730419200000, 890, 2330, 550, 1950, 3770],
29-
[1733011200000, 1440, 3770, 890, 3200, 5100]
30-
]
52+
dataset.value = generateRandomCandlestickData({ count: 100 })
3153
}, 2000)
3254
})
3355
@@ -65,6 +87,7 @@ function alterDataset() {
6587
}
6688
6789
const model = ref([
90+
{ key: 'type', def: 'ohlc', type: 'select', options: ['ohlc', 'candlestick']},
6891
{ key: 'loading', def: false, type: 'checkbox'},
6992
{ key: 'debug', def: false, type: 'checkbox'},
7093
{ key: 'responsive', def: false, type: 'checkbox'},
@@ -91,14 +114,25 @@ const model = ref([
91114
{ key: 'style.height', def: 316, type: 'number', min: 100, max: 1000},
92115
{ key: 'style.width', def: 512, type: 'number', min: 100, max: 1000},
93116
{ key: 'style.layout.padding.top', def: 0, type: 'number', min: 0, max: 100},
94-
{ key: 'style.layout.padding.right', def: 0, type: 'number', min: 0, max: 100},
117+
{ key: 'style.layout.padding.right', def: 12, type: 'number', min: 0, max: 100},
95118
{ key: 'style.layout.padding.bottom', def: 0, type: 'number', min: 0, max: 100},
96119
{ key: 'style.layout.padding.left', def: 0, type: 'number', min: 0, max: 100},
97120
{ key: 'style.layout.selector.color', def: '#1A1A1A', type: 'color'},
98121
{ key: 'style.layout.selector.opacity', def: 10, type: 'range', min: 0, max: 100},
99122
{ key: 'style.layout.grid.show', def: true, type: 'checkbox'},
100-
{ key: 'style.layout.grid.stroke', def: '#e1e5e8', type: 'color'},
101-
{ key: 'style.layout.grid.strokeWidth', def: 0.5, type: 'range', min: 0, max: 12, step: 0.5},
123+
{ key: 'style.layout.grid.stroke', def: '#CCCCCC', type: 'color'},
124+
{ key: 'style.layout.grid.strokeWidth', def: 1, type: 'range', min: 0, max: 12, step: 0.5},
125+
126+
{ key: 'style.layout.grid.horizontalLines.show', def: true, type: 'checkbox'},
127+
{ key: 'style.layout.grid.horizontalLines.strokeDasharray', def: 3, type: 'number', min: 0, max: 12},
128+
{ key: 'style.layout.grid.horizontalLines.stroke', def: '#FF0000', type: 'color'},
129+
{ key: 'style.layout.grid.horizontalLines.strokeWidth', def: 0.5, type: 'number', min: 0, max: 12, step: 0.1},
130+
131+
{ key: 'style.layout.grid.verticalLines.show', def: true, type: 'checkbox'},
132+
{ key: 'style.layout.grid.verticalLines.strokeDasharray', def: 3, type: 'number', min: 0, max: 12},
133+
{ key: 'style.layout.grid.verticalLines.stroke', def: '#0000FF', type: 'color'},
134+
{ key: 'style.layout.grid.verticalLines.strokeWidth', def: 0.5, type: 'number', min: 0, max: 12, step: 0.1},
135+
102136
{ key: 'style.layout.grid.xAxis.dataLabels.show', def: true, type: 'checkbox'},
103137
{ key: 'style.layout.grid.xAxis.dataLabels.fontSize', def: 10, type: 'number', min: 4, max: 12},
104138
{ key: 'style.layout.grid.xAxis.dataLabels.color', def: '#1A1A1A', type: 'color'},
@@ -120,7 +154,7 @@ const model = ref([
120154
{ key: 'style.layout.grid.yAxis.scale.max', def: null, type: 'number', min: 0, max: 10000},
121155
122156
{ key: 'style.layout.wick.stroke', def: '#1A1A1A', type: 'color'},
123-
{ key: 'style.layout.wick.strokeWidth', def: 3, type: 'number', min: 0, max: 12, step: 0.5},
157+
{ key: 'style.layout.wick.strokeWidth', def: 0.5, type: 'number', min: 0, max: 12, step: 0.5},
124158
{ key: 'style.layout.wick.extremity.shape', def: 'line', type: 'select', options: ['line', 'circle']},
125159
{ key: 'style.layout.wick.extremity.size', def: 'auto', type: 'select', options: ['auto', 5, 10, 20, 40]},
126160
{ key: 'style.layout.wick.extremity.color', def: '#1A1A1A', type: 'color'},
@@ -145,6 +179,8 @@ const model = ref([
145179
{ key: 'style.zoom.enableSelectionDrag', def: true, type: 'chexkbox'},
146180
{ key: 'style.zoom.focusOnDrag', def: true, type: 'checkbox'},
147181
{ key: 'style.zoom.focusRangeRatio', def: 0.2, type: 'number', min: 0.1, max: 0.9, step: 0.1},
182+
{ key: 'style.zoom.minimap.show', def: true, type: 'checkbox' },
183+
{ key: 'style.zoom.preview.enable', def: true, type: 'checkbox' },
148184
149185
{ key: 'style.title.text', def: 'At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis', type: 'text'},
150186
{ key: 'style.title.color', def: '#1A1A1A', type: 'color'},
@@ -238,13 +274,29 @@ const config = computed(() => {
238274
theme: currentTheme.value,
239275
style: {
240276
...c.style,
277+
zoom: {
278+
...c.style.zoom,
279+
useDefaultFormat: true,
280+
timeFormat: 'yyyy-MM-dd',
281+
customFormat: ({ datapoint, timeLabel }) => {
282+
return timeLabel
283+
}
284+
},
285+
tooltip: {
286+
...c.style.tooltip,
287+
useDefaultTimeFormat: false,
288+
timeFormat: 'yyyy-MM-dd'
289+
},
241290
layout: {
242291
...c.style.layout,
243292
grid: {
244293
...c.style.layout.grid,
245294
xAxis: {
246295
...c.style.layout.grid.xAxis,
247296
dataLabels: {
297+
showOnlyFirstAndLast: false,
298+
showOnlyAtModulo: true,
299+
modulo: 12,
248300
datetimeFormatter: {
249301
enable: true
250302
}
@@ -266,7 +318,13 @@ onMounted(async () => {
266318
const img = await local.value.getImage();
267319
console.log(img)
268320
}
269-
})
321+
});
322+
323+
const selectedX = ref(undefined);
324+
325+
function selectX({ datapoint, index, indexLabel}) {
326+
selectedX.value = index;
327+
}
270328
271329
</script>
272330

@@ -312,7 +370,7 @@ onMounted(async () => {
312370
<template #title>VueUiCandlestick</template>
313371

314372
<template #local>
315-
<LocalVueUiCandlestick :dataset="dataset" :config="isPropsToggled ? alternateConfig : config" :key="`local_${step}`" ref="local">
373+
<LocalVueUiCandlestick :selectedXIndex="selectedX" @selectX="selectX" :dataset="dataset" :config="isPropsToggled ? alternateConfig : config" :key="`local_${step}`" ref="local">
316374
<!-- <template #optionPdf>
317375
PRINT PDF
318376
</template>
@@ -339,7 +397,7 @@ onMounted(async () => {
339397
</template>
340398

341399
<template #VDUI-local>
342-
<LocalVueDataUi component="VueUiCandlestick" :dataset="isPropsToggled ? alternateDataset : dataset" :config="isPropsToggled ? alternateConfig : config" :key="`VDUI-lodal_${step}`" ref="vduiLocal">
400+
<LocalVueDataUi :selectedXIndex="selectedX" @selectX="selectX" component="VueUiCandlestick" :dataset="isPropsToggled ? alternateDataset : dataset" :config="isPropsToggled ? alternateConfig : config" :key="`VDUI-lodal_${step}`" ref="vduiLocal">
343401
<!-- <template #svg="{ svg }">
344402
<circle :cx="svg.width / 2" :cy="svg.height / 2" :r="30" fill="#42d392" />
345403
<text :x="svg.width / 2" :y="svg.height / 2" text-anchor="middle">#SVG</text>

src/components/vue-ui-candlestick.cy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('<VueUiCandlestick />', () => {
3333
cy.get('@scaleLabels').last().contains('160');
3434

3535
cy.log('X axis labels');
36-
cy.get('[data-cy="x-label"]').as('xLabels').should('exist').and('be.visible').and('have.length', 5);
36+
cy.get('[data-cy="x-label"]').as('xLabels').should('exist').and('be.visible').and('have.length', 10);
3737
cy.get('@xLabels').first().contains(dataset[0][0]);
3838
cy.get('@xLabels').last().contains(dataset.at(-1)[0]);
3939
});

0 commit comments

Comments
 (0)