diff --git a/apps/demos/Demos/Charts/Stock/Angular/app/app.component.html b/apps/demos/Demos/Charts/Stock/Angular/app/app.component.html
index b2564bc3cc80..489d11f83074 100644
--- a/apps/demos/Demos/Charts/Stock/Angular/app/app.component.html
+++ b/apps/demos/Demos/Charts/Stock/Angular/app/app.component.html
@@ -1,3 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
-
+
+
this.pan(-1),
+ };
+
+ panRightButtonOptions: DxButtonTypes.Properties = {
+ icon: 'chevronright',
+ hint: 'Pan Right',
+ onClick: () => this.pan(1),
+ };
+
+ zoomInButtonOptions: DxButtonTypes.Properties = {
+ icon: 'plus',
+ hint: 'Zoom In',
+ onClick: () => this.zoom(zoomFactor),
+ };
+
+ zoomOutButtonOptions: DxButtonTypes.Properties = {
+ icon: 'minus',
+ hint: 'Zoom Out',
+ onClick: () => this.zoom(1 / zoomFactor),
+ };
+
+ resetZoomButtonOptions: DxButtonTypes.Properties = {
+ icon: 'refresh',
+ hint: 'Reset Zoom',
+ onClick: () => this.resetZoom(),
+ };
+
+ constructor(service: Service, private changeDetectorRef: ChangeDetectorRef) {
this.stockPrices = service.getStockPrices();
+ this.dataMin = this.stockPrices[0].date.getTime();
+ this.dataMax = this.stockPrices[this.stockPrices.length - 1].date.getTime();
+ }
+
+ getRange() {
+ return {
+ start: (this.visualRange.startValue as Date).getTime(),
+ end: (this.visualRange.endValue as Date).getTime(),
+ };
+ }
+
+ setRange(start: number, end: number) {
+ const span = clamp(end - start, minVisibleSpanMs, this.dataMax - this.dataMin);
+ const center = (start + end) / 2;
+ const newStart = clamp(center - span / 2, this.dataMin, this.dataMax - span);
+
+ this.visualRange = {
+ startValue: new Date(newStart),
+ endValue: new Date(newStart + span),
+ };
+ this.changeDetectorRef.detectChanges();
+ }
+
+ pan(direction: number) {
+ const { start, end } = this.getRange();
+ const shift = (end - start) * panStepFraction * direction;
+ this.setRange(start + shift, end + shift);
+ }
+
+ zoom(factor: number) {
+ const { start, end } = this.getRange();
+ const center = (start + end) / 2;
+ const half = ((end - start) * factor) / 2;
+ this.setRange(center - half, center + half);
+ }
+
+ resetZoom() {
+ this.setRange(this.initialStart.getTime(), this.initialEnd.getTime());
}
- customizeTooltip(arg) {
+ customizeTooltip(arg: DxChartTypes.PointInfo) {
+ if (!('openValue' in arg)) {
+ return { text: '' };
+ }
return {
text: `Open: $${arg.openValue}
`
+ `Close: $${arg.closeValue}
`
diff --git a/apps/demos/Demos/Charts/Stock/Angular/app/app.service.ts b/apps/demos/Demos/Charts/Stock/Angular/app/app.service.ts
index 0240c22abc90..31902d64df8d 100644
--- a/apps/demos/Demos/Charts/Stock/Angular/app/app.service.ts
+++ b/apps/demos/Demos/Charts/Stock/Angular/app/app.service.ts
@@ -12,145 +12,46 @@ export class StockPrice {
c: number;
}
-const stockPrices: StockPrice[] = [{
- date: new Date(1994, 2, 1),
- l: 24.00,
- h: 25.00,
- o: 25.00,
- c: 24.875,
-}, {
- date: new Date(1994, 2, 2),
- l: 23.625,
- h: 25.125,
- o: 24.00,
- c: 24.875,
-}, {
- date: new Date(1994, 2, 3),
- l: 26.25,
- h: 28.25,
- o: 26.75,
- c: 27.00,
-}, {
- date: new Date(1994, 2, 4),
- l: 26.50,
- h: 27.875,
- o: 26.875,
- c: 27.25,
-}, {
- date: new Date(1994, 2, 7),
- l: 26.375,
- h: 27.50,
- o: 27.375,
- c: 26.75,
-}, {
- date: new Date(1994, 2, 8),
- l: 25.75,
- h: 26.875,
- o: 26.75,
- c: 26.00,
-}, {
- date: new Date(1994, 2, 9),
- l: 25.75,
- h: 26.75,
- o: 26.125,
- c: 26.25,
-}, {
- date: new Date(1994, 2, 10),
- l: 25.75,
- h: 26.375,
- o: 26.375,
- c: 25.875,
-}, {
- date: new Date(1994, 2, 11),
- l: 24.875,
- h: 26.125,
- o: 26.00,
- c: 25.375,
-}, {
- date: new Date(1994, 2, 14),
- l: 25.125,
- h: 26.00,
- o: 25.625,
- c: 25.75,
-}, {
- date: new Date(1994, 2, 15),
- l: 25.875,
- h: 26.625,
- o: 26.125,
- c: 26.375,
-}, {
- date: new Date(1994, 2, 16),
- l: 26.25,
- h: 27.375,
- o: 26.25,
- c: 27.25,
-}, {
- date: new Date(1994, 2, 17),
- l: 26.875,
- h: 27.25,
- o: 27.125,
- c: 26.875,
-}, {
- date: new Date(1994, 2, 18),
- l: 26.375,
- h: 27.125,
- o: 27.00,
- c: 27.125,
-}, {
- date: new Date(1994, 2, 21),
- l: 26.75,
- h: 27.875,
- o: 26.875,
- c: 27.75,
-}, {
- date: new Date(1994, 2, 22),
- l: 26.75,
- h: 28.375,
- o: 27.50,
- c: 27.00,
-}, {
- date: new Date(1994, 2, 23),
- l: 26.875,
- h: 28.125,
- o: 27.00,
- c: 28.00,
-}, {
- date: new Date(1994, 2, 24),
- l: 26.25,
- h: 27.875,
- o: 27.75,
- c: 27.625,
-}, {
- date: new Date(1994, 2, 25),
- l: 27.50,
- h: 28.75,
- o: 27.75,
- c: 28.00,
-}, {
- date: new Date(1994, 2, 28),
- l: 25.75,
- h: 28.25,
- o: 28.00,
- c: 27.25,
-}, {
- date: new Date(1994, 2, 29),
- l: 26.375,
- h: 27.50,
- o: 27.50,
- c: 26.875,
-}, {
- date: new Date(1994, 2, 30),
- l: 25.75,
- h: 27.50,
- o: 26.375,
- c: 26.25,
-}, {
- date: new Date(1994, 2, 31),
- l: 24.75,
- h: 27.00,
- o: 26.50,
- c: 25.25,
-}];
+function generateStockData(startDate: Date, days: number): StockPrice[] {
+ let seed = 12345;
+
+ function random(): number {
+ seed = (seed * 16807) % 2147483647;
+ return (seed - 1) / 2147483646;
+ }
+
+ function randomOffset(amplitude: number): number {
+ return (random() - 0.5) * amplitude;
+ }
+
+ const data: StockPrice[] = [];
+ const current = new Date(startDate);
+ let price = 25;
+
+ while (data.length < days) {
+ const day = current.getDay();
+ if (day !== 0 && day !== 6) {
+ const open = price + randomOffset(1.5);
+ const close = open + randomOffset(1.5);
+ const high = Math.max(open, close) + random() * 0.8;
+ const low = Math.min(open, close) - random() * 0.8;
+
+ data.push({
+ date: new Date(current),
+ o: +open.toFixed(2),
+ h: +high.toFixed(2),
+ l: +low.toFixed(2),
+ c: +close.toFixed(2),
+ });
+
+ price = close;
+ }
+ current.setDate(current.getDate() + 1);
+ }
+ return data;
+}
+
+const stockPrices: StockPrice[] = generateStockData(new Date(1994, 3, 1), 65);
@Injectable()
export class Service {
diff --git a/apps/demos/Demos/Charts/Stock/React/App.tsx b/apps/demos/Demos/Charts/Stock/React/App.tsx
index fa73f5c3571e..4d776069b5dd 100644
--- a/apps/demos/Demos/Charts/Stock/React/App.tsx
+++ b/apps/demos/Demos/Charts/Stock/React/App.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback, useMemo, useState } from 'react';
import Chart, {
CommonSeriesSettings,
Series,
@@ -8,12 +8,41 @@ import Chart, {
Format,
ValueAxis,
Title,
+ ZoomAndPan,
+ ScrollBar,
+ Legend,
Export,
Tooltip,
} from 'devextreme-react/chart';
import type { ChartTypes } from 'devextreme-react/chart';
+import type { VisualRange } from 'devextreme-react/common/charts';
+import type { ButtonTypes } from 'devextreme-react/button';
+import Toolbar, { Item } from 'devextreme-react/toolbar';
import { dataSource } from './data.ts';
+const dayMs = 24 * 60 * 60 * 1000;
+const panStepFraction = 0.25;
+const zoomFactor = 0.75;
+const minVisibleSpanMs = 3 * dayMs;
+const minVisualRangeLength = { days: 3 };
+
+const initialStart = new Date(1994, 3, 14, 12);
+const initialEnd = new Date(1994, 3, 29, 12);
+
+const dataMin = dataSource[0].date.getTime();
+const dataMax = dataSource[dataSource.length - 1].date.getTime();
+
+function clamp(value: number, min: number, max: number): number {
+ return Math.min(Math.max(value, min), max);
+}
+
+function getRange(range: VisualRange) {
+ return {
+ start: (range.startValue as Date).getTime(),
+ end: (range.endValue as Date).getTime(),
+ };
+}
+
function customizeTooltip(arg: ChartTypes.PointInfo): Record {
if (!('openValue' in arg)) {
return { text: '' };
@@ -28,34 +57,129 @@ function customizeTooltip(arg: ChartTypes.PointInfo): Record {
}
function App() {
+ const [visualRange, setVisualRange] = useState({
+ startValue: initialStart,
+ endValue: initialEnd,
+ });
+
+ const onVisualRangeChange = useCallback((range: VisualRange | (Date | number | string)[]) => {
+ setVisualRange(range as VisualRange);
+ }, []);
+
+ const setRange = useCallback((start: number, end: number) => {
+ const span = clamp(end - start, minVisibleSpanMs, dataMax - dataMin);
+ const center = (start + end) / 2;
+ const newStart = clamp(center - span / 2, dataMin, dataMax - span);
+
+ setVisualRange({
+ startValue: new Date(newStart),
+ endValue: new Date(newStart + span),
+ });
+ }, []);
+
+ const pan = useCallback((direction: number) => {
+ const { start, end } = getRange(visualRange);
+ const shift = (end - start) * panStepFraction * direction;
+ setRange(start + shift, end + shift);
+ }, [visualRange, setRange]);
+
+ const zoom = useCallback((factor: number) => {
+ const { start, end } = getRange(visualRange);
+ const center = (start + end) / 2;
+ const half = ((end - start) * factor) / 2;
+ setRange(center - half, center + half);
+ }, [visualRange, setRange]);
+
+ const resetZoom = useCallback(() => {
+ setRange(initialStart.getTime(), initialEnd.getTime());
+ }, [setRange]);
+
+ const panLeftButtonOptions = useMemo(() => ({
+ icon: 'chevronleft',
+ hint: 'Pan Left',
+ onClick: () => pan(-1),
+ }), [pan]);
+
+ const panRightButtonOptions = useMemo(() => ({
+ icon: 'chevronright',
+ hint: 'Pan Right',
+ onClick: () => pan(1),
+ }), [pan]);
+
+ const zoomInButtonOptions = useMemo(() => ({
+ icon: 'plus',
+ hint: 'Zoom In',
+ onClick: () => zoom(zoomFactor),
+ }), [zoom]);
+
+ const zoomOutButtonOptions = useMemo(() => ({
+ icon: 'minus',
+ hint: 'Zoom Out',
+ onClick: () => zoom(1 / zoomFactor),
+ }), [zoom]);
+
+ const resetZoomButtonOptions = useMemo(() => ({
+ icon: 'refresh',
+ hint: 'Reset Zoom',
+ onClick: resetZoom,
+ }), [resetZoom]);
+
return (
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
);
}
diff --git a/apps/demos/Demos/Charts/Stock/React/data.ts b/apps/demos/Demos/Charts/Stock/React/data.ts
index 29303780dd9e..1130d8f41409 100644
--- a/apps/demos/Demos/Charts/Stock/React/data.ts
+++ b/apps/demos/Demos/Charts/Stock/React/data.ts
@@ -1,139 +1,48 @@
-export const dataSource = [{
- date: new Date(1994, 2, 1),
- l: 24.00,
- h: 25.00,
- o: 25.00,
- c: 24.875,
-}, {
- date: new Date(1994, 2, 2),
- l: 23.625,
- h: 25.125,
- o: 24.00,
- c: 24.875,
-}, {
- date: new Date(1994, 2, 3),
- l: 26.25,
- h: 28.25,
- o: 26.75,
- c: 27.00,
-}, {
- date: new Date(1994, 2, 4),
- l: 26.50,
- h: 27.875,
- o: 26.875,
- c: 27.25,
-}, {
- date: new Date(1994, 2, 7),
- l: 26.375,
- h: 27.50,
- o: 27.375,
- c: 26.75,
-}, {
- date: new Date(1994, 2, 8),
- l: 25.75,
- h: 26.875,
- o: 26.75,
- c: 26.00,
-}, {
- date: new Date(1994, 2, 9),
- l: 25.75,
- h: 26.75,
- o: 26.125,
- c: 26.25,
-}, {
- date: new Date(1994, 2, 10),
- l: 25.75,
- h: 26.375,
- o: 26.375,
- c: 25.875,
-}, {
- date: new Date(1994, 2, 11),
- l: 24.875,
- h: 26.125,
- o: 26.00,
- c: 25.375,
-}, {
- date: new Date(1994, 2, 14),
- l: 25.125,
- h: 26.00,
- o: 25.625,
- c: 25.75,
-}, {
- date: new Date(1994, 2, 15),
- l: 25.875,
- h: 26.625,
- o: 26.125,
- c: 26.375,
-}, {
- date: new Date(1994, 2, 16),
- l: 26.25,
- h: 27.375,
- o: 26.25,
- c: 27.25,
-}, {
- date: new Date(1994, 2, 17),
- l: 26.875,
- h: 27.25,
- o: 27.125,
- c: 26.875,
-}, {
- date: new Date(1994, 2, 18),
- l: 26.375,
- h: 27.125,
- o: 27.00,
- c: 27.125,
-}, {
- date: new Date(1994, 2, 21),
- l: 26.75,
- h: 27.875,
- o: 26.875,
- c: 27.75,
-}, {
- date: new Date(1994, 2, 22),
- l: 26.75,
- h: 28.375,
- o: 27.50,
- c: 27.00,
-}, {
- date: new Date(1994, 2, 23),
- l: 26.875,
- h: 28.125,
- o: 27.00,
- c: 28.00,
-}, {
- date: new Date(1994, 2, 24),
- l: 26.25,
- h: 27.875,
- o: 27.75,
- c: 27.625,
-}, {
- date: new Date(1994, 2, 25),
- l: 27.50,
- h: 28.75,
- o: 27.75,
- c: 28.00,
-}, {
- date: new Date(1994, 2, 28),
- l: 25.75,
- h: 28.25,
- o: 28.00,
- c: 27.25,
-}, {
- date: new Date(1994, 2, 29),
- l: 26.375,
- h: 27.50,
- o: 27.50,
- c: 26.875,
-}, {
- date: new Date(1994, 2, 30),
- l: 25.75,
- h: 27.50,
- o: 26.375,
- c: 26.25,
-}, {
- date: new Date(1994, 2, 31),
- l: 24.75,
- h: 27.00,
- o: 26.50,
- c: 25.25,
-}];
+export interface StockPrice {
+ date: Date;
+ l: number;
+ h: number;
+ o: number;
+ c: number;
+}
+
+function generateStockData(startDate: Date, days: number): StockPrice[] {
+ let seed = 12345;
+
+ function random(): number {
+ seed = (seed * 16807) % 2147483647;
+ return (seed - 1) / 2147483646;
+ }
+
+ function randomOffset(amplitude: number): number {
+ return (random() - 0.5) * amplitude;
+ }
+
+ const data: StockPrice[] = [];
+ const current = new Date(startDate);
+ let price = 25;
+
+ while (data.length < days) {
+ const day = current.getDay();
+ if (day !== 0 && day !== 6) {
+ const open = price + randomOffset(1.5);
+ const close = open + randomOffset(1.5);
+ const high = Math.max(open, close) + random() * 0.8;
+ const low = Math.min(open, close) - random() * 0.8;
+
+ data.push({
+ date: new Date(current),
+ o: +open.toFixed(2),
+ h: +high.toFixed(2),
+ l: +low.toFixed(2),
+ c: +close.toFixed(2),
+ });
+
+ price = close;
+ }
+ current.setDate(current.getDate() + 1);
+ }
+ return data;
+}
+
+export const dataSource = generateStockData(new Date(1994, 3, 1), 65);
diff --git a/apps/demos/Demos/Charts/Stock/ReactJs/App.js b/apps/demos/Demos/Charts/Stock/ReactJs/App.js
index 24cf604fc115..083d15f11825 100644
--- a/apps/demos/Demos/Charts/Stock/ReactJs/App.js
+++ b/apps/demos/Demos/Charts/Stock/ReactJs/App.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback, useMemo, useState } from 'react';
import Chart, {
CommonSeriesSettings,
Series,
@@ -8,11 +8,33 @@ import Chart, {
Format,
ValueAxis,
Title,
+ ZoomAndPan,
+ ScrollBar,
+ Legend,
Export,
Tooltip,
} from 'devextreme-react/chart';
+import Toolbar, { Item } from 'devextreme-react/toolbar';
import { dataSource } from './data.js';
+const dayMs = 24 * 60 * 60 * 1000;
+const panStepFraction = 0.25;
+const zoomFactor = 0.75;
+const minVisibleSpanMs = 3 * dayMs;
+const minVisualRangeLength = { days: 3 };
+const initialStart = new Date(1994, 3, 14, 12);
+const initialEnd = new Date(1994, 3, 29, 12);
+const dataMin = dataSource[0].date.getTime();
+const dataMax = dataSource[dataSource.length - 1].date.getTime();
+function clamp(value, min, max) {
+ return Math.min(Math.max(value, min), max);
+}
+function getRange(range) {
+ return {
+ start: range.startValue.getTime(),
+ end: range.endValue.getTime(),
+ };
+}
function customizeTooltip(arg) {
if (!('openValue' in arg)) {
return { text: '' };
@@ -25,44 +47,173 @@ function customizeTooltip(arg) {
};
}
function App() {
+ const [visualRange, setVisualRange] = useState({
+ startValue: initialStart,
+ endValue: initialEnd,
+ });
+ const onVisualRangeChange = useCallback((range) => {
+ setVisualRange(range);
+ }, []);
+ const setRange = useCallback((start, end) => {
+ const span = clamp(end - start, minVisibleSpanMs, dataMax - dataMin);
+ const center = (start + end) / 2;
+ const newStart = clamp(center - span / 2, dataMin, dataMax - span);
+ setVisualRange({
+ startValue: new Date(newStart),
+ endValue: new Date(newStart + span),
+ });
+ }, []);
+ const pan = useCallback(
+ (direction) => {
+ const { start, end } = getRange(visualRange);
+ const shift = (end - start) * panStepFraction * direction;
+ setRange(start + shift, end + shift);
+ },
+ [visualRange, setRange],
+ );
+ const zoom = useCallback(
+ (factor) => {
+ const { start, end } = getRange(visualRange);
+ const center = (start + end) / 2;
+ const half = ((end - start) * factor) / 2;
+ setRange(center - half, center + half);
+ },
+ [visualRange, setRange],
+ );
+ const resetZoom = useCallback(() => {
+ setRange(initialStart.getTime(), initialEnd.getTime());
+ }, [setRange]);
+ const panLeftButtonOptions = useMemo(
+ () => ({
+ icon: 'chevronleft',
+ hint: 'Pan Left',
+ onClick: () => pan(-1),
+ }),
+ [pan],
+ );
+ const panRightButtonOptions = useMemo(
+ () => ({
+ icon: 'chevronright',
+ hint: 'Pan Right',
+ onClick: () => pan(1),
+ }),
+ [pan],
+ );
+ const zoomInButtonOptions = useMemo(
+ () => ({
+ icon: 'plus',
+ hint: 'Zoom In',
+ onClick: () => zoom(zoomFactor),
+ }),
+ [zoom],
+ );
+ const zoomOutButtonOptions = useMemo(
+ () => ({
+ icon: 'minus',
+ hint: 'Zoom Out',
+ onClick: () => zoom(1 / zoomFactor),
+ }),
+ [zoom],
+ );
+ const resetZoomButtonOptions = useMemo(
+ () => ({
+ icon: 'refresh',
+ hint: 'Reset Zoom',
+ onClick: resetZoom,
+ }),
+ [resetZoom],
+ );
return (
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ >
);
}
export default App;
diff --git a/apps/demos/Demos/Charts/Stock/ReactJs/data.js b/apps/demos/Demos/Charts/Stock/ReactJs/data.js
index 8ac0d34d2404..0361f3fea288 100644
--- a/apps/demos/Demos/Charts/Stock/ReactJs/data.js
+++ b/apps/demos/Demos/Charts/Stock/ReactJs/data.js
@@ -1,163 +1,33 @@
-export const dataSource = [
- {
- date: new Date(1994, 2, 1),
- l: 24.0,
- h: 25.0,
- o: 25.0,
- c: 24.875,
- },
- {
- date: new Date(1994, 2, 2),
- l: 23.625,
- h: 25.125,
- o: 24.0,
- c: 24.875,
- },
- {
- date: new Date(1994, 2, 3),
- l: 26.25,
- h: 28.25,
- o: 26.75,
- c: 27.0,
- },
- {
- date: new Date(1994, 2, 4),
- l: 26.5,
- h: 27.875,
- o: 26.875,
- c: 27.25,
- },
- {
- date: new Date(1994, 2, 7),
- l: 26.375,
- h: 27.5,
- o: 27.375,
- c: 26.75,
- },
- {
- date: new Date(1994, 2, 8),
- l: 25.75,
- h: 26.875,
- o: 26.75,
- c: 26.0,
- },
- {
- date: new Date(1994, 2, 9),
- l: 25.75,
- h: 26.75,
- o: 26.125,
- c: 26.25,
- },
- {
- date: new Date(1994, 2, 10),
- l: 25.75,
- h: 26.375,
- o: 26.375,
- c: 25.875,
- },
- {
- date: new Date(1994, 2, 11),
- l: 24.875,
- h: 26.125,
- o: 26.0,
- c: 25.375,
- },
- {
- date: new Date(1994, 2, 14),
- l: 25.125,
- h: 26.0,
- o: 25.625,
- c: 25.75,
- },
- {
- date: new Date(1994, 2, 15),
- l: 25.875,
- h: 26.625,
- o: 26.125,
- c: 26.375,
- },
- {
- date: new Date(1994, 2, 16),
- l: 26.25,
- h: 27.375,
- o: 26.25,
- c: 27.25,
- },
- {
- date: new Date(1994, 2, 17),
- l: 26.875,
- h: 27.25,
- o: 27.125,
- c: 26.875,
- },
- {
- date: new Date(1994, 2, 18),
- l: 26.375,
- h: 27.125,
- o: 27.0,
- c: 27.125,
- },
- {
- date: new Date(1994, 2, 21),
- l: 26.75,
- h: 27.875,
- o: 26.875,
- c: 27.75,
- },
- {
- date: new Date(1994, 2, 22),
- l: 26.75,
- h: 28.375,
- o: 27.5,
- c: 27.0,
- },
- {
- date: new Date(1994, 2, 23),
- l: 26.875,
- h: 28.125,
- o: 27.0,
- c: 28.0,
- },
- {
- date: new Date(1994, 2, 24),
- l: 26.25,
- h: 27.875,
- o: 27.75,
- c: 27.625,
- },
- {
- date: new Date(1994, 2, 25),
- l: 27.5,
- h: 28.75,
- o: 27.75,
- c: 28.0,
- },
- {
- date: new Date(1994, 2, 28),
- l: 25.75,
- h: 28.25,
- o: 28.0,
- c: 27.25,
- },
- {
- date: new Date(1994, 2, 29),
- l: 26.375,
- h: 27.5,
- o: 27.5,
- c: 26.875,
- },
- {
- date: new Date(1994, 2, 30),
- l: 25.75,
- h: 27.5,
- o: 26.375,
- c: 26.25,
- },
- {
- date: new Date(1994, 2, 31),
- l: 24.75,
- h: 27.0,
- o: 26.5,
- c: 25.25,
- },
-];
+function generateStockData(startDate, days) {
+ let seed = 12345;
+ function random() {
+ seed = (seed * 16807) % 2147483647;
+ return (seed - 1) / 2147483646;
+ }
+ function randomOffset(amplitude) {
+ return (random() - 0.5) * amplitude;
+ }
+ const data = [];
+ const current = new Date(startDate);
+ let price = 25;
+ while (data.length < days) {
+ const day = current.getDay();
+ if (day !== 0 && day !== 6) {
+ const open = price + randomOffset(1.5);
+ const close = open + randomOffset(1.5);
+ const high = Math.max(open, close) + random() * 0.8;
+ const low = Math.min(open, close) - random() * 0.8;
+ data.push({
+ date: new Date(current),
+ o: +open.toFixed(2),
+ h: +high.toFixed(2),
+ l: +low.toFixed(2),
+ c: +close.toFixed(2),
+ });
+ price = close;
+ }
+ current.setDate(current.getDate() + 1);
+ }
+ return data;
+}
+export const dataSource = generateStockData(new Date(1994, 3, 1), 65);
diff --git a/apps/demos/Demos/Charts/Stock/Vue/App.vue b/apps/demos/Demos/Charts/Stock/Vue/App.vue
index 5d6a15657757..d09a8271510a 100644
--- a/apps/demos/Demos/Charts/Stock/Vue/App.vue
+++ b/apps/demos/Demos/Charts/Stock/Vue/App.vue
@@ -1,4 +1,31 @@
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
+