Skip to content

Commit 6504b2b

Browse files
authored
Merge pull request #2 from QuantForgeOrg/dev
v0.5.2
2 parents affc5e2 + 2dded48 commit 6504b2b

File tree

6 files changed

+119
-21
lines changed

6 files changed

+119
-21
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.5.2] - 2025-12-20
9+
10+
### Added
11+
12+
- **Enhanced Plot Types**
13+
- Multi-color support for Line plots, allowing different colors per segment.
14+
- New Step plot type for discrete value visualization.
15+
- **Documentation & Examples**
16+
- Live demos integrated into documentation pages.
17+
- Additional demo examples showcasing plugin usage and features.
18+
- Plugin integration examples in demo charts.
19+
20+
### Fixed
21+
22+
- Zoom controller improvements and tweaks for better user experience.
23+
- Chart.js integration fixes for proper module loading.
24+
- Documentation page rendering and theme consistency.
25+
- Updated internal GitHub repository links.
26+
27+
### Changed
28+
29+
- Enhanced demo pages with more comprehensive examples.
30+
- Improved documentation structure and navigation.
31+
- Optimized chart sizing for various use cases.
32+
833
## [0.5.0] - 2025-12-17 (first public release)
934

1035
### Added

docs/demos/full.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<h1>Full featured Demo</h1>
2424
<p>
2525
This demo uses the
26-
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library to load the maret data and calculate multiple
26+
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library to load the market data and calculate multiple
2727
indicators.
2828
</p>
2929
<hr />
@@ -71,14 +71,16 @@ <h1>Full featured Demo</h1>
7171
volume: k.volume,
7272
}));
7373

74+
const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
75+
7476
// Initialize Chart
7577
const chartContainer = document.getElementById('main-chart');
7678
window.chart = new QFChart.QFChart(chartContainer, {
7779
title: 'BTC/USDT', // Custom title
7880
height: '800px',
7981
padding: 0.2,
8082
databox: {
81-
position: 'right',
83+
position: isMobileDevice ? 'floating' : 'right',
8284
},
8385
dataZoom: {
8486
visible: true,

docs/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ permalink: /
2525
<div id="container">
2626
<!-- <h1>QFChart Library Demo</h1> -->
2727
<p>
28-
This is a demo of the QFChart library. It uses the
29-
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library to get the data and the indicators.
28+
This is demo uses <a href="https://github.com/QuantForgeOrg/QFChart" target="_blank">QFChart</a> for visualization and
29+
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library for market data loading and indicators processing.
3030
</p>
3131
<hr />
3232
<div id="main-chart"></div>
@@ -40,7 +40,7 @@ permalink: /
4040
<script src="./js/indicators/sqzmom.js"></script>
4141
<script src="./js/indicators/macd.js"></script>
4242
<script src="./js/indicators/instit-bias.js"></script>
43-
<script src="./js/chart.js"></script>
43+
<script src="./js/chart-script.js"></script>
4444

4545
---
4646

src/components/SeriesBuilder.ts

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,29 @@ export class SeriesBuilder {
6969
plot.data.forEach((point) => {
7070
const index = timeToIndex.get(point.time);
7171
if (index !== undefined) {
72-
const offsetIndex = index + dataIndexOffset;
73-
dataArray[offsetIndex] = point.value;
74-
colorArray[offsetIndex] = point.options?.color || plot.options.color;
72+
const plotOffset = point.options?.offset ?? plot.options.offset ?? 0;
73+
const offsetIndex = index + dataIndexOffset + plotOffset;
74+
75+
if (offsetIndex >= 0 && offsetIndex < totalDataLength) {
76+
let value = point.value;
77+
const pointColor = point.options?.color;
78+
79+
// TradingView compatibility: if color is 'na' (NaN, null, or "na"), break the line
80+
const isNaColor =
81+
pointColor === null ||
82+
pointColor === 'na' ||
83+
pointColor === 'NaN' ||
84+
(typeof pointColor === 'number' && isNaN(pointColor));
85+
86+
if (isNaColor) {
87+
value = null;
88+
}
89+
90+
dataArray[offsetIndex] = value;
91+
colorArray[offsetIndex] = pointColor || plot.options.color;
92+
}
7593
}
7694
});
77-
7895
switch (plot.options.style) {
7996
case 'histogram':
8097
case 'columns':
@@ -163,24 +180,75 @@ export class SeriesBuilder {
163180
});
164181
break;
165182

183+
case 'step':
184+
series.push({
185+
name: seriesName,
186+
type: 'custom',
187+
xAxisIndex: xAxisIndex,
188+
yAxisIndex: yAxisIndex,
189+
renderItem: (params: any, api: any) => {
190+
const x = api.value(0);
191+
const y = api.value(1);
192+
if (isNaN(y) || y === null) return;
193+
194+
const coords = api.coord([x, y]);
195+
const width = api.size([1, 0])[0];
196+
197+
return {
198+
type: 'line',
199+
shape: {
200+
x1: coords[0] - width / 2,
201+
y1: coords[1],
202+
x2: coords[0] + width / 2,
203+
y2: coords[1],
204+
},
205+
style: {
206+
stroke: colorArray[params.dataIndex] || plot.options.color,
207+
lineWidth: plot.options.linewidth || 1,
208+
},
209+
silent: true,
210+
};
211+
},
212+
data: dataArray.map((val, i) => [i, val]),
213+
});
214+
break;
215+
166216
case 'line':
167217
default:
168218
series.push({
169219
name: seriesName,
170-
type: 'line',
220+
type: 'custom',
171221
xAxisIndex: xAxisIndex,
172222
yAxisIndex: yAxisIndex,
173-
smooth: true,
174-
showSymbol: false,
175-
data: dataArray.map((val, i) => ({
176-
value: val,
177-
itemStyle: colorArray[i] ? { color: colorArray[i] } : undefined,
178-
})),
179-
itemStyle: { color: plot.options.color },
180-
lineStyle: {
181-
width: plot.options.linewidth || 1,
182-
color: plot.options.color,
223+
renderItem: (params: any, api: any) => {
224+
const index = params.dataIndex;
225+
if (index === 0) return; // Need at least two points for a line segment
226+
227+
const y2 = api.value(1);
228+
const y1 = api.value(2); // We'll store prevValue in the data
229+
230+
if (y2 === null || isNaN(y2) || y1 === null || isNaN(y1)) return;
231+
232+
const p1 = api.coord([index - 1, y1]);
233+
const p2 = api.coord([index, y2]);
234+
235+
return {
236+
type: 'line',
237+
shape: {
238+
x1: p1[0],
239+
y1: p1[1],
240+
x2: p2[0],
241+
y2: p2[1],
242+
},
243+
style: {
244+
stroke: colorArray[index] || plot.options.color,
245+
lineWidth: plot.options.linewidth || 1,
246+
},
247+
silent: true,
248+
};
183249
},
250+
// Data format: [index, value, prevValue]
251+
data: dataArray.map((val, i) => [i, val, i > 0 ? dataArray[i - 1] : null]),
184252
});
185253
break;
186254
}

src/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,18 @@ export interface IndicatorPoint {
1414
value: number | null;
1515
options?: {
1616
color?: string;
17+
offset?: number;
1718
};
1819
}
1920

20-
export type IndicatorStyle = 'line' | 'columns' | 'histogram' | 'circles' | 'cross' | 'background';
21+
export type IndicatorStyle = 'line' | 'step' | 'columns' | 'histogram' | 'circles' | 'cross' | 'background';
2122

2223
export interface IndicatorOptions {
2324
style: IndicatorStyle;
2425
color: string;
26+
offset?: number;
2527
linewidth?: number;
28+
smooth?: boolean;
2629
}
2730

2831
export interface IndicatorPlot {

0 commit comments

Comments
 (0)