File: README.md
Demos | Documentation | Reddit
TradingView Lightweight Charts™ are one of the smallest and fastest financial HTML5 charts.
The Lightweight Charts™ library is the best choice for you if you want to display financial data as an interactive chart on your web page without affecting your web page loading speed and performance.
It is the best choice for you if you want to replace static image charts with interactive ones.
The size of the library is close to static images but if you have dozens of image charts on a web page then using this library can make the size of your web page smaller.
Take a look at awesome-tradingview for related projects created by our community members.
The library provides a rich set of charting capabilities out of the box, but developers can also extend its functionality by building custom plugins. See the interactive plugin examples here, or check out plugin-examples/README.md for more details.
Installing
es6 via npm
npm install lightweight-chartsLatest master build
To try the latest master build without waiting for a release (powered by pkg.pr.new):
npm install https://pkg.pr.new/lightweight-charts@masterThe import and usage below applies to both npm installation options:
import { createChart, LineSeries } from 'lightweight-charts';
const chart = createChart(document.body, { width: 400, height: 300 });
const lineSeries = chart.addSeries(LineSeries);
lineSeries.setData([
{ time: '2019-04-11', value: 80.01 },
{ time: '2019-04-12', value: 96.63 },
{ time: '2019-04-13', value: 76.64 },
{ time: '2019-04-14', value: 81.89 },
{ time: '2019-04-15', value: 74.43 },
{ time: '2019-04-16', value: 80.01 },
{ time: '2019-04-17', value: 96.63 },
{ time: '2019-04-18', value: 76.64 },
{ time: '2019-04-19', value: 81.89 },
{ time: '2019-04-20', value: 74.43 },
]);CDN
You can use unpkg:
https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js
The standalone version creates window.LightweightCharts object with all exports from esm version:
const chart = LightweightCharts.createChart(document.body, { width: 400, height: 300 });
const lineSeries = chart.addSeries(LightweightCharts.LineSeries);
lineSeries.setData([
{ time: '2019-04-11', value: 80.01 },
{ time: '2019-04-12', value: 96.63 },
{ time: '2019-04-13', value: 76.64 },
{ time: '2019-04-14', value: 81.89 },
{ time: '2019-04-15', value: 74.43 },
{ time: '2019-04-16', value: 80.01 },
{ time: '2019-04-17', value: 96.63 },
{ time: '2019-04-18', value: 76.64 },
{ time: '2019-04-19', value: 81.89 },
{ time: '2019-04-20', value: 74.43 },
]);Build Variants
| Dependencies included | Mode | ES module | IIFE (window.LightweightCharts) |
|---|---|---|---|
| No | PROD | lightweight-charts.production.mjs |
N/A |
| No | DEV | lightweight-charts.development.mjs |
N/A |
| Yes (standalone) | PROD | lightweight-charts.standalone.production.mjs |
lightweight-charts.standalone.production.js |
| Yes (standalone) | DEV | lightweight-charts.standalone.development.mjs |
lightweight-charts.standalone.development.js |
AI coding assistants
This repository ships an Agent Skill that teaches AI coding assistants how to work with Lightweight Charts™ - the v5 API conventions, the mental model, and the common time, scale, marker, plugin, and wrapper foot-guns.
Install it into your project with the skills CLI:
npx skills add https://github.com/tradingview/lightweight-chartsThis makes the skill available to compatible assistants (such as Claude Code, Codex, etc.), streamlining your workflow: they scaffold charts, wire up series and data, and answer API questions against the current v5 conventions out of the box - instead of relying on outdated snippets and stumbling into common foot-guns.
Development
See BUILDING.md for instructions on how to build lightweight-charts from source.
License
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License.
You may obtain a copy of the License at LICENSE file.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
This software incorporates several parts of tslib (https://github.com/Microsoft/tslib, (c) Microsoft Corporation) that are covered by BSD Zero Clause License.
This license requires specifying TradingView as the product creator.
You shall add the "attribution notice" from the NOTICE file and a link to https://www.tradingview.com/ to the page of your website or mobile application that is available to your users.
As thanks for creating this product, we'd be grateful if you add it in a prominent place.
You can use the attributionLogo chart option for displaying an appropriate link to https://www.tradingview.com/ on the chart itself, which will satisfy the link requirement.
File: debug/README.md
Debug Folder
This folder is dedicated to creating and testing debug files that won't be committed to the repository. It provides a safe environment for contributors to experiment and test without impacting the main codebase.
It also offers an easy way to manage multiple sandboxes and includes a default template to help you get started quickly.
Usage
Before using the package, initialize the common root directory for all experiments by running:
npm run initCreating a Sandbox
To create a new sandbox, use the following command:
npm run create <NAME>Replace <NAME> with the desired name for your new sandbox, which will be created under playground/<NAME>.d.
By default, the sandbox includes lightweight-charts, typescript, and vite. Additional packages can be installed as needed, and any installed package will be shared across all sandboxes, both existing and future.
Running a Sandbox
Ensure that lightweight-charts is built, as it depends on your local copy.
To (re)build lightweight-charts, run:
npm run build --prefix ..To run a sandbox, use the serve command. This starts a web server, compiles TypeScript, and enables live reload when files change.
npm run serve <NAME>To run sandbox against production (minified) build of the lightweight-charts:
npm run serve:prod <NAME>Removing a Sandbox
If you need to delete a sandbox, use the following command:
npm run remove <NAME>This will remove everything under playground/<NAME>.d, including the directory itself.
File: packages/create-lwc-plugin/template-common/README.md
_PLUGINNAME_ - Lightweight Charts™ Plugin
Description of the Plugin.
- Developed for Lightweight Charts version:
v5.0.0
Running Locally
npm install
npm run devVisit localhost:5173 in the browser.
Compiling
npm run compileCheck the output in the dist folder.
Publishing To NPM
You can configure the contents of the package's package.json within thecompile.mjs script.
Once you have compiled the plugin (see above section) then you can publish the
package to NPM with these commands:
cd dist
npm publishHint: append --dry-run to the end of the publish command to see the results of
the publish command without actually uploading the package to NPM.
File: packages/create-lwc-plugin/README.md
create-lwc-plugin
create-lwc-plugin is an npm package designed to simplify the process of
creating a new plugin for Lightweight Charts™. With this generator, you can
quickly scaffold a project from a template for either
- a Drawing primitive plugin, or
- a Custom series plugin.
By using this wizard-like tool, you can customize the initial setup of their
plugin project by answering a few questions. This allows for a seamless and
efficient starting point, saving valuable time and effort.
Whether you are developing a new Drawing primitive plugin or a Custom series
plugin for Lightweight Charts, this generator provides a structured and
organized foundation. It ensures that your plugin adheres to the best practices
and conventions of Lightweight Charts, making it easier to develop, maintain,
and contribute to the community.
Getting started with your Lightweight Charts plugin development has never been
easier. Let the Lightweight Charts™ Plugin Scaffold Generator
(create-lwc-plugin) handle the initial setup, so you can focus on creating
outstanding plugins for Lightweight Charts™.
✨ Need some examples for inspiration? Check out the
plugin-examples
folder in the Lightweight Charts repo.
Scaffolding Your First Lightweight Charts™ Plugin
With NPM:
npm create lwc-plugin@latestWith Yarn:
yarn create lwc-pluginWith PNPM:
pnpm create lwc-pluginUsing the generated project
Running Locally (during development)
npm install
npm run devVisit localhost:5173 in the browser.
Compiling the Plugin
npm run compileCheck the output in the dist folder.
Publishing To NPM
You can configure the contents of the package's package.json within thecompile.mjs script.
Once you have compiled the plugin (see above section) then you can publish the
package to NPM with these commands:
cd dist
npm publishHint: append --dry-run to the end of the publish command to see the results of
the publish command without actually uploading the package to NPM.
File: plugin-examples/README.md
Lightweight Charts™ Plugin Examples
This folder contains a collection of example plugins designed to extend the
functionality of Lightweight Charts™ and inspire the development of your own
plugins.
Disclaimer: These plugins are provided as-is, and are primarily intended as
proof-of-concept examples and starting points. They have not been fully
optimized for production and may not receive updates or improvements over time.
We believe in the power of community collaboration, and we warmly welcome any
pull requests (PRs) aimed at enhancing and fixing the existing examples.
Additionally, we encourage you to create your own plugins and share them with
the community. We would be delighted to showcase the best plugins our users
create in this readme document.
✨ If you have something cool to share or if you need assistance, please don't
hesitate to get in touch.
🚀 Need a starting point for your plugin idea? Check out
create-lwc-plugin package.
📊 You can view a demo page of the plugins within this repo at his link:
Plugin Examples
Learning More
Running Locally
To run this repo locally, follow these steps:
Clone the repo to your local machine
First build the library
shellnpm install npm run build:prodSwitch to the Plugin Examples Folder, install and start the development server
shellcd plugin-examples npm install npm run devVisit
localhost:5173in the browser.
Compiling the Examples
npm run compileCheck the output in the compiled folder.
Using an Example
Once you have compiled the examples then simply copy that folder into your
project and import the JS module in your code.
Copy the compiled plugin folder into your project, example:
plugins/background-shade-series(fromcompiled/background-shade-series)Within your project, you can import the class as follows:
jsimport { BackgroundShadeSeries } from '../plugins/background-shade-series/background-shade-series'; // ... const backgroundShadeSeriesPlugin = new BackgroundShadeSeries(); const myCustomSeries = chart.addCustomSeries(backgroundShadeSeriesPlugin, { lowValue: 0, highValue: 1000, });
Creating your own Plugin
create-lwc-plugin is an npm
package designed to simplify the process of creating a new plugin for
Lightweight Charts™. With this generator, you can quickly scaffold a project
from a template for either
- a Drawing primitive plugin, or
- a Custom series plugin.
You can get started with this simple command:
npm create lwc-plugin@latestFile: website/docs/migrations/from-v2-to-v3.md
From v2 to v3
Lightweight Charts™ library 3.0 announces the major improvements: supporting two price scales and improving the time scale API.
In order of keep the API clear and consistent, we decided to allow breaking change of the API.
In this document you can find the migration guide from the previous version to 3.0.
Time Scale API
Previously, to handle changing visible time range you needed to use subscribeVisibleTimeRangeChange and unsubscribeVisibleTimeRangeChange to subscribe and unsubscribe from visible range events.
These methods were available in the chart object (e.g. you call it like chart.subscribeVisibleTimeRangeChange(func)).
In 3.0 in order to make API more consistent with the new API we decided to move these methods to ITimeScaleApi
(along with the new subscription methods ITimeScaleApi.subscribeVisibleLogicalRangeChange and ITimeScaleApi.unsubscribeVisibleLogicalRangeChange).
So, to migrate your code to 3.0 you just need to replace:
chart.subscribeVisibleTimeRangeChangewithchart.timeScale().subscribeVisibleTimeRangeChangechart.unsubscribeVisibleTimeRangeChangewithchart.timeScale().unsubscribeVisibleTimeRangeChange
Two price scales
We understand disadvantages of breaking changes in the API, so we have not removed support of the current API at all, but have deprecated it, so the most common cases will continue to work.
You can refer to the new API here.
Following are migration rules.
Default behavior
Default behavior is not changed. If you do not specify price scale options, the chart will have the right price scale visible and all the series will assign to it.
Left price scale
If you need the price scale to be drawn on the left side, you should make the following changes.
instead of
const chart = LightweightCharts.createChart(container, {
priceScale: {
position: 'left',
},
});use
const chart = LightweightCharts.createChart(container, {
rightPriceScale: {
visible: false,
},
leftPriceScale: {
visible: true,
},
});then specify target price scale while creating a series:
const histSeries = chart.addHistogramSeries({
priceScaleId: 'left',
});New version fully supports this case via the old API, however this support will be removed in the future releases.
No price scale
To create chart without any visible price scale, instead of
const chart = LightweightCharts.createChart(container, {
priceScale: {
position: 'none',
},
});use
const chart = LightweightCharts.createChart(container, {
leftPriceScale: {
visible: false,
},
rightPriceScale: {
visible: false,
},
});New version fully supports this case via the old API, however this support will be removed in the future releases.
Creating overlay
To create an overlay series, instead of
const histogramSeries = chart.addHistogramSeries({
overlay: true,
});use
const histogramSeries = chart.addHistogramSeries({
// or any other _the same_ id for all overlay series
priceScaleId: '',
});New version fully supports this case via the old API, however this support will be removed in the future releases.
Move price scale from right to left or vice versa
To do this, instead of
const chart = LightweightCharts.createChart(container);
const mainSeries = chart.addLineSeries();
// ...
chart.applyOptions({
priceScale: {
position: 'left',
},
});use
const chart = LightweightCharts.createChart(container);
const mainSeries = chart.addLineSeries();
// ...
chart.applyOptions({
leftPriceScale: {
visible: true,
},
rightPriceScale: {
visible: false,
},
});
mainSeries.applyOptions({
priceScaleId: 'left',
});New version does not support this case via the old API, so, if you use it, you should migrate your code in order of keeping it working.
File: website/docs/migrations/from-v3-to-v4.md
From v3 to v4
In this document you can find the migration guide from the previous version v3 to v4.
Exported enum `LasPriceAnimationMode` has been removed
Please use LastPriceAnimationMode instead.
`scaleMargins` option has been removed from series options
Previously, you could do something like the following:
const series = chart.addLineSeries({
scaleMargins: { /* options here */},
});And scaleMargins option was applied to series' price scale as scaleMargins option.
Since v4 this option won't be applied to the price scale and will be just ignored (if you're using TypeScript you will get a compilation error).
To fix this, you need to apply these options to series' price scale:
const series = chart.addLineSeries();
series.priceScale().applyOptions({
scaleMargins: { /* options here */},
});`backgroundColor` from `layout` options has been removed
If you want to have solid background color you need to use background property instead, e.g. instead of:
const chart = createChart({
layout: {
backgroundColor: 'red',
},
});use
const chart = createChart({
layout: {
background: {
type: ColorType.Solid,
color: 'red',
},
},
});`overlay` property of series options has been removed
Please follow the guide for migrating from v2 to v3 where this option was deprecated.
`priceScale` option has been removed
Please follow the guide for migrating from v2 to v3.
`priceScale()` method of chart API now requires to provide price scale id
Before v4 you could write the following code:
const priceScale = chart.priceScale();And in priceScale you had a right price scale if it is visible and a left price scale otherwise.
Since v4 you have to provide an ID of price scale explicitly, e.g. if you want to get a right price scale you need to provide 'right':
const rightPriceScale = chart.priceScale('right');
const leftPriceScale = chart.priceScale('left');`drawTicks` from `leftPriceScale` and `rightPriceScale` options has been renamed to `ticksVisible`
Since v4 you have to use ticksVisible instead of drawTicks.
const chart = createChart({
leftPriceScale: {
ticksVisible: false,
},
rightPriceScale: {
ticksVisible: false,
},
});Also this option is off by default.
The type of outbound time values has been changed
Affected API:
IChartApi.subscribeClick(viaMouseEventParams.time)IChartApi.subscribeCrosshairMove(viaMouseEventParams.time)LocalizationOptions.timeFormatter(via argument ofTimeFormatterFn)TimeScaleOptions.tickMarkFormatter(via argument ofTickMarkFormatter)
Previously the type of an inbound time (a values you provide to the library, e.g. in ISeriesApi.setData) was different from an outbound one (a values the library provides to your code, e.g. an argument of LocalizationOptions.timeFormatter).
So the difference between types was that outbound time couldn't be a business day string.
Since v4 we improved our API in this matter and now the library will return exactly the same values back for all time-related properties.
Thus, if you provide a string to your series in ISeriesApi.setData, you'll receive exactly the same value back:
series.setData([
{ time: '2001-01-01', value: 1 },
]);
chart.applyOptions({
localization: {
timeFormatter: time => time, // will be '2001-01-01' for the bar above
},
timeScale: {
tickMarkFormatter: time => time, // will be '2001-01-01' for the bar above
},
});
chart.subscribeCrosshairMove(param => {
console.log(param.time); // will be '2001-01-01' if you hover the bar above
});
chart.subscribeClick(param => {
console.log(param.time); // will be '2001-01-01' if you click on the bar above
});Handling this breaking change depends on your needs and your handlers, but generally speaking you need to convert provided time to a desired format manually if it is required.
For example, you could use provided helpers to check the type of a time:
import {
createChart,
isUTCTimestamp,
isBusinessDay,
} from 'lightweight-charts';
const chart = createChart(document.body);
chart.subscribeClick(param => {
if (param.time === undefined) {
// the time is undefined, i.e. there is no any data point where a time could be received from
return;
}
if (isUTCTimestamp(param.time)) {
// param.time is UTCTimestamp
} else if (isBusinessDay(param.time)) {
// param.time is a BusinessDay object
} else {
// param.time is a business day string in ISO format, e.g. `'2010-01-01'`
}
});`seriesPrices` property from `MouseEventParams` has been removed
Affected API:
The property seriesPrices of MouseEventParams has been removed.
Instead, you can use MouseEventParams.seriesData - it is pretty similar to the old seriesPrices, but it contains series' data items instead of just prices:
lineSeries.setData([{ time: '2001-01-01', value: 1 }]);
barSeries.setData([{ time: '2001-01-01', open: 5, high: 10, low: 1, close: 7 }]);
chart.subscribeCrosshairMove(param => {
console.log(param.seriesData.get(lineSeries)); // { time: '2001-01-01', value: 1 } or undefined
console.log(param.seriesData.get(barSeries)); // { time: '2001-01-01', open: 5, high: 10, low: 1, close: 7 } or undefined
});`MouseEventParams` field `hoveredMarkerId` was renamed to `hoveredObjectId`
Since v4 you have to use hoveredObjectId instead of hoveredMarkerId.
chart.subscribeCrosshairMove(param => {
console.log(param.hoveredObjectId);
});
chart.subscribeClick(param => {
console.log(param.hoveredObjectId);
});File: website/docs/migrations/from-v4-to-v5.md
From v4 to v5
In this document you can find the migration guide from the previous version v4
to v5.
Table of Contents
Series changes
Overview of Changes {#overview-changes-series}
- Unified series creation API using single
addSeriesfunction - Better tree-shaking support
- Individual series types must now be imported separately (for ESM)
Migration Steps {#migration-steps-series}
Replace all series creation calls with the new addSeries syntax. Here's how the migration works for each series type:
Before (v4) {#v4-series}
// Example with Line Series in v4
import { createChart } from 'lightweight-charts';
const chart = createChart(container, {});
const lineSeries = chart.addLineSeries({ color: 'red' });After (v5) {#v5-series}
// Example with Line Series in v5
import { createChart, LineSeries } from 'lightweight-charts';
const chart = createChart(container, {});
const lineSeries = chart.addSeries(LineSeries, { color: 'red' });Migration Reference {#migration-reference-series}
Here's how to migrate each series type:
| v4 Method | v5 Method |
|---|---|
chart.addLineSeries(options) |
chart.addSeries(LineSeries, options) |
chart.addAreaSeries(options) |
chart.addSeries(AreaSeries, options) |
chart.addBarSeries(options) |
chart.addSeries(BarSeries, options) |
chart.addBaselineSeries(options) |
chart.addSeries(BaselineSeries, options) |
chart.addCandlestickSeries(options) |
chart.addSeries(CandlestickSeries, options) |
chart.addHistogramSeries(options) |
chart.addSeries(HistogramSeries, options) |
Usage Examples {#usage-examples-series}
ESM (ES Modules):
import { createChart, LineSeries } from 'lightweight-charts';
const chart = createChart(container, {});
const lineSeries = chart.addSeries(LineSeries, { color: 'red' });UMD (Universal Module Definition):
const chart = LightweightCharts.createChart(container, {});
const lineSeries = chart.addSeries(LightweightCharts.LineSeries, { color: 'red' });Note: Make sure to import the specific series type (e.g., LineSeries, AreaSeries) along with createChart when using ES Modules. For UMD builds, all series types are available under the LightweightCharts namespace.
Series Markers
Overview of Changes {#overview-changes-markers}
- Markers moved to separate primitive for optimized bundle size
- New
createSeriesMarkersfunction required - Marker management through dedicated primitive instance
Migration Steps {#migration-steps-markers}
Before (v4) {#v4-markers}
// Markers were directly managed through the series instance
series.setMarkers([
{
time: '2019-04-09',
position: 'aboveBar',
color: 'black',
shape: 'arrowDown',
},
]);
// Getting markers
const markers = series.markers();After (v5) {#v5-markers}
// Import the markers primitive
import { createSeriesMarkers } from 'lightweight-charts';
// Create a markers primitive instance
const seriesMarkers = createSeriesMarkers(series, [
{
time: '2019-04-09',
position: 'aboveBar',
color: 'black',
shape: 'arrowDown',
},
]);
// Getting markers
const markers = seriesMarkers.markers();
// Updating markers
seriesMarkers.setMarkers([/* new markers */]);
// Remove all markers
seriesMarkers.setMarkers([]);Key Changes {#key-changes-markers}
- You must now import
createSeriesMarkersseparately - Instead of calling methods directly on the series instance, create a markers primitive using
createSeriesMarkers - The markers API is now accessed through the markers primitive instance
- The marker configuration object format remains the same
- This change results in smaller bundle sizes when markers aren't used
If your application doesn't use markers, you can now benefit from a smaller bundle size as this functionality is no longer included in the core package.
Watermarks
Overview of Changes {#overview-changes-watermarks}
In the new version of Lightweight Charts, the watermark feature has undergone significant changes:
- Extraction from Core: The watermark functionality has been extracted from the core library.
- Re-implementation: It's now re-implemented as a Pane Primitive (plugin) included within the library.
- Improved Tree-shaking: This change makes the feature more tree-shakeable, potentially reducing bundle sizes for users who don't need watermarks.
- Added an Image Watermark Primitive: In addition to the usual text based watermark, there is now
an image watermark feature provided by thecreateImageWatermarkplugin.
Migration Steps {#migration-steps-watermarks}
Before (v4) {#v4-watermarks}
const chart = createChart(container, {
watermark: {
text: 'Watermark Text',
color: 'rgba(255,0,0,0.5)',
},
});After (v5) {#v5-watermarks}
import { createChart, createTextWatermark } from 'lightweight-charts';
const chart = createChart(container, options);
const firstPane = chart.panes()[0];
createTextWatermark(firstPane, {
horzAlign: 'center',
vertAlign: 'center',
lines: [{
text: 'Watermark Text',
color: 'rgba(255,0,0,0.5)',
fontSize: 50,
}],
});Accessing the New TextWatermark
The TextWatermark plugin is now available as follows:
- ESM builds: Import
createTextWatermarkdirectly. - Standalone script build: Access via
LightweightCharts.createTextWatermark.
Changes in Options
The options structure for watermarks has been revised:
- Multiple Lines: The plugin now supports multiple lines of text.
- Text Options: Text-related options are now defined per line within the
linesproperty of the options object.
Attaching the Watermark
To use the plugin, you need pass a pane object to the createTextWatermark function. The pane object specifies where the watermark should be attached:
- Single Pane: If you're using only one pane, you can easily fetch it using
chart.panes()[0]. - Multiple Panes: For charts with multiple panes, you'll need to specify which pane to attach the watermark to.
Example: Implementing a Text Watermark
Here's a comprehensive example demonstrating how to implement a text watermark in the new version:
const chart = createChart(container, options);
const mainSeries = chart.addSeries(LineSeries);
mainSeries.setData(generateData());
const firstPane = chart.panes()[0];
createTextWatermark(firstPane, {
horzAlign: 'center',
vertAlign: 'center',
lines: [
{
text: 'Hello',
color: 'rgba(255,0,0,0.5)',
fontSize: 100,
fontStyle: 'bold',
},
{
text: 'This is a text watermark',
color: 'rgba(0,0,255,0.5)',
fontSize: 50,
fontStyle: 'italic',
fontFamily: 'monospace',
},
],
});Plugin Typings
Overview of Changes {#overview-changes-plugins}
Some of the plugin types and interfaces have been renamed due to the additional
of Pane Primitives.
ISeriesPrimitivePaneView→IPrimitivePaneViewISeriesPrimitivePaneRenderer→IPrimitivePaneRendererSeriesPrimitivePaneViewZOrder→PrimitivePaneViewZOrder
File: website/docs/plugins/pixel-perfect-rendering/widths/candlestick.md
sidebar_position: 0
sidebar_label: Candlesticks
pagination_title: Candlestick Widths
title: Candlestick Width Calculations
keywords:
- plugins
- extensions
- rendering
- canvas
- bitmap
- media
- pixels
- candlestick
- width
:::tip
It is recommend that you first read the Pixel Perfect Rendering page.
:::
The following functions can be used to get the calculated width that the library would use for a candlestick at a specific bar spacing and device pixel ratio.
Below a bar spacing of 4, the library will attempt to use as large a width as possible without the possibility of overlapping, whilst above 4 then the width will start to trend towards an 80% width of the available space.
:::warning
It is expected that candles can overlap slightly at smaller bar spacings (more pronounced on lower resolution devices). This produces a more readable chart. If you need to ensure that bars can never overlap then rather use the widths for Columns or the full bar width calculation.
:::
function optimalCandlestickWidth(
barSpacing: number,
pixelRatio: number
): number {
const barSpacingSpecialCaseFrom = 2.5;
const barSpacingSpecialCaseTo = 4;
const barSpacingSpecialCaseCoeff = 3;
if (barSpacing >= barSpacingSpecialCaseFrom && barSpacing <= barSpacingSpecialCaseTo) {
return Math.floor(barSpacingSpecialCaseCoeff * pixelRatio);
}
// coeff should be 1 on small barspacing and go to 0.8 while bar spacing grows
const barSpacingReducingCoeff = 0.2;
const coeff =
1 -
(barSpacingReducingCoeff *
Math.atan(
Math.max(barSpacingSpecialCaseTo, barSpacing) - barSpacingSpecialCaseTo
)) /
(Math.PI * 0.5);
const res = Math.floor(barSpacing * coeff * pixelRatio);
const scaledBarSpacing = Math.floor(barSpacing * pixelRatio);
const optimal = Math.min(res, scaledBarSpacing);
return Math.max(Math.floor(pixelRatio), optimal);
}
/**
* Calculates the candlestick width that the library would use for the current
* bar spacing.
* @param barSpacing - bar spacing in media coordinates
* @param horizontalPixelRatio - horizontal pixel ratio
* @returns The width (in bitmap coordinates) that the chart would use to draw a candle body
*/
export function candlestickWidth(
barSpacing: number,
horizontalPixelRatio: number
): number {
let width = optimalCandlestickWidth(barSpacing, horizontalPixelRatio);
if (width >= 2) {
const wickWidth = Math.floor(horizontalPixelRatio);
if (wickWidth % 2 !== width % 2) {
width--;
}
}
return width;
}File: website/docs/plugins/pixel-perfect-rendering/widths/columns.md
sidebar_position: 0
sidebar_label: Columns
pagination_title: Histogram Column Widths
title: Histogram Column Width Calculations
keywords:
- plugins
- extensions
- rendering
- canvas
- bitmap
- media
- pixels
- histogram
- column
- width
:::tip
It is recommend that you first read the Pixel Perfect Rendering page.
:::
The following functions can be used to get the calculated width that the library would use for a histogram column at a specific bar spacing and device pixel ratio.
You can use the calculateColumnPositionsInPlace function instead of the calculateColumnPositions function to perform the calculation on an existing array of items without needing to create additional arrays (which is more efficient). It is recommended that you memoize the majority of the calculations below to improve the rendering performance.
/* Detailed source-code truncated for AI context efficiency. */