Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.2] - 2025-12-20

### Added

- **Enhanced Plot Types**
- Multi-color support for Line plots, allowing different colors per segment.
- New Step plot type for discrete value visualization.
- **Documentation & Examples**
- Live demos integrated into documentation pages.
- Additional demo examples showcasing plugin usage and features.
- Plugin integration examples in demo charts.

### Fixed

- Zoom controller improvements and tweaks for better user experience.
- Chart.js integration fixes for proper module loading.
- Documentation page rendering and theme consistency.
- Updated internal GitHub repository links.

### Changed

- Enhanced demo pages with more comprehensive examples.
- Improved documentation structure and navigation.
- Optimized chart sizing for various use cases.

## [0.5.0] - 2025-12-17 (first public release)

### Added
Expand Down
6 changes: 4 additions & 2 deletions docs/demos/full.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<h1>Full featured Demo</h1>
<p>
This demo uses the
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library to load the maret data and calculate multiple
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library to load the market data and calculate multiple
indicators.
</p>
<hr />
Expand Down Expand Up @@ -71,14 +71,16 @@ <h1>Full featured Demo</h1>
volume: k.volume,
}));

const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);

// Initialize Chart
const chartContainer = document.getElementById('main-chart');
window.chart = new QFChart.QFChart(chartContainer, {
title: 'BTC/USDT', // Custom title
height: '800px',
padding: 0.2,
databox: {
position: 'right',
position: isMobileDevice ? 'floating' : 'right',
},
dataZoom: {
visible: true,
Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ permalink: /
<div id="container">
<!-- <h1>QFChart Library Demo</h1> -->
<p>
This is a demo of the QFChart library. It uses the
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library to get the data and the indicators.
This is demo uses <a href="https://github.com/QuantForgeOrg/QFChart" target="_blank">QFChart</a> for visualization and
<a href="https://github.com/QuantForgeOrg/PineTS" target="_blank">PineTS</a> library for market data loading and indicators processing.
</p>
<hr />
<div id="main-chart"></div>
Expand All @@ -40,7 +40,7 @@ permalink: /
<script src="./js/indicators/sqzmom.js"></script>
<script src="./js/indicators/macd.js"></script>
<script src="./js/indicators/instit-bias.js"></script>
<script src="./js/chart.js"></script>
<script src="./js/chart-script.js"></script>

---

Expand Down
File renamed without changes.
98 changes: 83 additions & 15 deletions src/components/SeriesBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,29 @@ export class SeriesBuilder {
plot.data.forEach((point) => {
const index = timeToIndex.get(point.time);
if (index !== undefined) {
const offsetIndex = index + dataIndexOffset;
dataArray[offsetIndex] = point.value;
colorArray[offsetIndex] = point.options?.color || plot.options.color;
const plotOffset = point.options?.offset ?? plot.options.offset ?? 0;
const offsetIndex = index + dataIndexOffset + plotOffset;

if (offsetIndex >= 0 && offsetIndex < totalDataLength) {
let value = point.value;
const pointColor = point.options?.color;

// TradingView compatibility: if color is 'na' (NaN, null, or "na"), break the line
const isNaColor =
pointColor === null ||
pointColor === 'na' ||
pointColor === 'NaN' ||
(typeof pointColor === 'number' && isNaN(pointColor));

if (isNaColor) {
value = null;
}

dataArray[offsetIndex] = value;
colorArray[offsetIndex] = pointColor || plot.options.color;
}
}
});

switch (plot.options.style) {
case 'histogram':
case 'columns':
Expand Down Expand Up @@ -163,24 +180,75 @@ export class SeriesBuilder {
});
break;

case 'step':
series.push({
name: seriesName,
type: 'custom',
xAxisIndex: xAxisIndex,
yAxisIndex: yAxisIndex,
renderItem: (params: any, api: any) => {
const x = api.value(0);
const y = api.value(1);
if (isNaN(y) || y === null) return;

const coords = api.coord([x, y]);
const width = api.size([1, 0])[0];

return {
type: 'line',
shape: {
x1: coords[0] - width / 2,
y1: coords[1],
x2: coords[0] + width / 2,
y2: coords[1],
},
style: {
stroke: colorArray[params.dataIndex] || plot.options.color,
lineWidth: plot.options.linewidth || 1,
},
silent: true,
};
},
data: dataArray.map((val, i) => [i, val]),
});
break;

case 'line':
default:
series.push({
name: seriesName,
type: 'line',
type: 'custom',
xAxisIndex: xAxisIndex,
yAxisIndex: yAxisIndex,
smooth: true,
showSymbol: false,
data: dataArray.map((val, i) => ({
value: val,
itemStyle: colorArray[i] ? { color: colorArray[i] } : undefined,
})),
itemStyle: { color: plot.options.color },
lineStyle: {
width: plot.options.linewidth || 1,
color: plot.options.color,
renderItem: (params: any, api: any) => {
const index = params.dataIndex;
if (index === 0) return; // Need at least two points for a line segment

const y2 = api.value(1);
const y1 = api.value(2); // We'll store prevValue in the data

if (y2 === null || isNaN(y2) || y1 === null || isNaN(y1)) return;

const p1 = api.coord([index - 1, y1]);
const p2 = api.coord([index, y2]);

return {
type: 'line',
shape: {
x1: p1[0],
y1: p1[1],
x2: p2[0],
y2: p2[1],
},
style: {
stroke: colorArray[index] || plot.options.color,
lineWidth: plot.options.linewidth || 1,
},
silent: true,
};
},
// Data format: [index, value, prevValue]
data: dataArray.map((val, i) => [i, val, i > 0 ? dataArray[i - 1] : null]),
});
break;
}
Expand Down
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,18 @@ export interface IndicatorPoint {
value: number | null;
options?: {
color?: string;
offset?: number;
};
}

export type IndicatorStyle = 'line' | 'columns' | 'histogram' | 'circles' | 'cross' | 'background';
export type IndicatorStyle = 'line' | 'step' | 'columns' | 'histogram' | 'circles' | 'cross' | 'background';

export interface IndicatorOptions {
style: IndicatorStyle;
color: string;
offset?: number;
linewidth?: number;
smooth?: boolean;
}

export interface IndicatorPlot {
Expand Down