From 013424ecbf672db80646fe51ee48b187e9b71cec Mon Sep 17 00:00:00 2001 From: Romain Francois Date: Wed, 8 Feb 2023 12:44:08 +0000 Subject: [PATCH] Release v4.0.0 --- tests/e2e/graphics/helpers/screenshoter.ts | 2 +- website/docs/android.md | 2 +- website/docs/ios.md | 4 +- website/package.json | 3 +- .../import-lightweight-charts-version.ts | 14 ++ website/versioned_docs/version-4.0/android.md | 119 +++++++++++ website/versioned_docs/version-4.0/intro.md | 184 ++++++++++++++++ website/versioned_docs/version-4.0/ios.md | 100 +++++++++ .../version-4.0/migrations/_category_.yml | 2 + .../version-4.0/migrations/from-v2-to-v3.md | 158 ++++++++++++++ .../version-4.0/migrations/from-v3-to-v4.md | 200 ++++++++++++++++++ .../versioned_docs/version-4.0/price-scale.md | 40 ++++ .../version-4.0/series-types.md | 160 ++++++++++++++ .../versioned_docs/version-4.0/time-scale.md | 37 ++++ .../versioned_docs/version-4.0/time-zones.md | 114 ++++++++++ .../version-4.0-sidebars.json | 33 +++ website/versions.json | 1 + 17 files changed, 1168 insertions(+), 5 deletions(-) create mode 100644 website/versioned_docs/version-4.0/android.md create mode 100644 website/versioned_docs/version-4.0/intro.md create mode 100644 website/versioned_docs/version-4.0/ios.md create mode 100644 website/versioned_docs/version-4.0/migrations/_category_.yml create mode 100644 website/versioned_docs/version-4.0/migrations/from-v2-to-v3.md create mode 100644 website/versioned_docs/version-4.0/migrations/from-v3-to-v4.md create mode 100644 website/versioned_docs/version-4.0/price-scale.md create mode 100644 website/versioned_docs/version-4.0/series-types.md create mode 100644 website/versioned_docs/version-4.0/time-scale.md create mode 100644 website/versioned_docs/version-4.0/time-zones.md create mode 100644 website/versioned_sidebars/version-4.0-sidebars.json diff --git a/tests/e2e/graphics/helpers/screenshoter.ts b/tests/e2e/graphics/helpers/screenshoter.ts index 2ebc4e51c2..e4cb190165 100644 --- a/tests/e2e/graphics/helpers/screenshoter.ts +++ b/tests/e2e/graphics/helpers/screenshoter.ts @@ -114,7 +114,7 @@ export class Screenshoter { throw new Error(errors.join('\n')); } - const pageScreenshotPNG = PNG.sync.read(await page.screenshot({ encoding: 'binary' })); + const pageScreenshotPNG = PNG.sync.read(await page.screenshot({ encoding: 'binary' }) as Buffer); const additionalScreenshotDataURL = await page.evaluate(() => { const testCaseWindow = window as unknown as TestCaseWindow; if (!testCaseWindow.checkChartScreenshot) { diff --git a/website/docs/android.md b/website/docs/android.md index d6534d4a92..2cd00e160d 100644 --- a/website/docs/android.md +++ b/website/docs/android.md @@ -42,7 +42,7 @@ In `/gradle_module/build.gradle` ```groovy dependencies { //... - implementation 'com.tradingview:lightweightcharts:3.8.0' + implementation 'com.tradingview:lightweightcharts:4.0.0' } ``` diff --git a/website/docs/ios.md b/website/docs/ios.md index 42ac771150..7f38d826ae 100644 --- a/website/docs/ios.md +++ b/website/docs/ios.md @@ -31,7 +31,7 @@ Requires iOS 10.0+ [CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate LightweightCharts into your Xcode project using CocoaPods, specify it in your `Podfile`: ```ruby -pod 'LightweightCharts', '~> 3.8.0' +pod 'LightweightCharts', '~> 4.0.0' ``` ### Swift Package Manager @@ -42,7 +42,7 @@ Once you have your Swift package set up, adding LightweightCharts as a dependenc ```swift dependencies: [ - .package(url: "https://github.com/tradingview/LightweightChartsIOS", .upToNextMajor(from: "3.8.0")) + .package(url: "https://github.com/tradingview/LightweightChartsIOS", .upToNextMajor(from: "4.0.0")) ] ``` diff --git a/website/package.json b/website/package.json index 7d0dde0f04..1e0407aae7 100644 --- a/website/package.json +++ b/website/package.json @@ -20,9 +20,10 @@ "@types/react": "~17.0.39", "cross-env": "~7.0.3", "docusaurus-plugin-typedoc": "0.17.5", - "lightweight-charts": "~3.8.0", + "lightweight-charts": "~4.0.0", "lightweight-charts-local": "file:..", "lightweight-charts-3.8": "npm:lightweight-charts@~3.8.0", + "lightweight-charts-4.0": "npm:lightweight-charts@~4.0.0", "prism-react-renderer": "~1.3.5", "raw-loader": "~4.0.2", "react": "~17.0.2", diff --git a/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts b/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts index 320f20dd99..3f97a8183c 100644 --- a/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts +++ b/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts @@ -2,15 +2,18 @@ import type { Version } from '../../../../versions'; export type LightweightChartsApi38 = typeof import('lightweight-charts-3.8'); +export type LightweightChartsApi40 = typeof import('lightweight-charts-4.0'); export type LightweightChartsApiCurrent = typeof import('../../../../..'); export interface LightweightChartsApiTypeMap { '3.8': LightweightChartsApi38; + '4.0': LightweightChartsApi40; current: LightweightChartsApiCurrent; } export interface LightweightChartsCreateChartTypeMap { '3.8': LightweightChartsApi38['createChart']; + '4.0': LightweightChartsApi40['createChart']; current: LightweightChartsApiCurrent['createChart']; } @@ -46,6 +49,17 @@ export const importLightweightChartsVersion: LightweightChartsApiGetters = { return { module, createChart }; }, + '4.0': async (window: Window) => { + const module = await import('lightweight-charts-4.0'); + + const createChart: typeof module.createChart = (container: string | HTMLElement, options?: Parameters[1]) => { + const result = module.createChart(container, options); + addResizeHandler(window, container as HTMLElement, result.resize.bind(result)); + return result; + }; + + return { module, createChart }; + }, current: async () => { const module = await import('../../../../..'); diff --git a/website/versioned_docs/version-4.0/android.md b/website/versioned_docs/version-4.0/android.md new file mode 100644 index 0000000000..2cd00e160d --- /dev/null +++ b/website/versioned_docs/version-4.0/android.md @@ -0,0 +1,119 @@ +--- +id: android +description: You can use Lightweight Charts inside an Android application. To use Lightweight Charts in that context, you can use our Android wrapper, which will allow you to interact with lightweight charts library, which will be rendered in a web view. +keywords: + - charts + - android + - canvas + - charting library + - charting + - html5 charts + - financial charting library +sidebar_position: 7 +--- + +# Android wrapper + +:::note +You can find the source code of the Lightweight Charts Android wrapper in [this repository](https://github.com/tradingview/lightweight-charts-android). +::: + +You can use Lightweight Charts inside an Android application. To use Lightweight Charts in that context, you can use our Android wrapper, which will allow you to interact with lightweight charts library, which will be rendered in a web view. + +## Installation + +:::info +Requires minSdkVersion 21, and installed WebView with support of ES6 +::: + +In `/build.gradle` + +```groovy +allprojects { + repositories { + google() + mavenCentral() + } +} +``` + +In `/gradle_module/build.gradle` + +```groovy +dependencies { + //... + implementation 'com.tradingview:lightweightcharts:4.0.0' +} +``` + +## Usage + +Add view to the layout. + +```xml + + + + + +``` + +Configure the chart layout. + +```kotlin +charts_view.api.applyOptions { + layout = layoutOptions { + background = SolidColor(Color.LTGRAY) + textColor = Color.BLACK.toIntColor() + } + localization = localizationOptions { + locale = "ru-RU" + priceFormatter = PriceFormatter(template = "{price:#2:#3}$") + timeFormatter = TimeFormatter( + locale = "ru-RU", + dateTimeFormat = DateTimeFormat.DATE_TIME + ) + } +} +``` + +Add any series to the chart and store a reference to it. + +```kotlin +lateinit var histogramSeries: SeriesApi +charts_view.api.addHistogramSeries( + onSeriesCreated = { series -> + histogramSeries = series + } +) +``` + +Add data to the series. + +```kotlin +val data = listOf( + HistogramData(Time.BusinessDay(2019, 6, 11), 40.01f), + HistogramData(Time.BusinessDay(2019, 6, 12), 52.38f), + HistogramData(Time.BusinessDay(2019, 6, 13), 36.30f), + HistogramData(Time.BusinessDay(2019, 6, 14), 34.48f), + WhitespaceData(Time.BusinessDay(2019, 6, 15)), + WhitespaceData(Time.BusinessDay(2019, 6, 16)), + HistogramData(Time.BusinessDay(2019, 6, 17), 41.50f), + HistogramData(Time.BusinessDay(2019, 6, 18), 34.82f) +) +histogramSeries.setData(data) +``` + +## How to run the provided example + +The [GitHub repository](https://github.com/tradingview/lightweight-charts-android) for lightweight-charts-android contains an example of the library in action. +You can run the example (LighweightCharts.app) by cloning the repository and opening it in Android Studio. You will need to have [NodeJS/NPM](https://nodejs.org/) installed. diff --git a/website/versioned_docs/version-4.0/intro.md b/website/versioned_docs/version-4.0/intro.md new file mode 100644 index 0000000000..0f7d41f1e5 --- /dev/null +++ b/website/versioned_docs/version-4.0/intro.md @@ -0,0 +1,184 @@ +--- +slug: / +id: intro +sidebar_position: 0 +--- + +# Getting started + +## Requirements + +First of all, Lightweight Charts is _a client-side_ library. +This means that it does not and cannot work on the server-side (i.e. NodeJS), at least out of the box. + +The code of `lightweight-charts` package is targeted to [_es2016_ language specification](https://262.ecma-international.org/7.0/). +Thus, all the browsers you will have to work with should support this language revision (see [this compatibility table](https://kangax.github.io/compat-table/es2016plus/)). +If you need to support the previous revisions, you could try to setup a transpilation of the package to the target you need to support in your build system (e.g. by using Babel). +If you'll have any issues with that, please raise an issue on github with the details and we'll investigate possible ways to solve it. + +## Installation + +The first thing you need to do to use `lightweight-charts` is to install it from [npm](https://www.npmjs.com/): + +```console +npm install --save lightweight-charts +``` + +_Note that the package is shipped with TypeScript declarations, so you can easily use it within TypeScript code._ + +### Build variants + +The library ships with the following build variants: + +|Dependencies included|Mode|ES module|CommonJS ⚠️|IIFE (`window.LightweightCharts`)| +|-|-|-|-|-| +|No|PROD|`lightweight-charts.production.mjs`|`lightweight-charts.production.cjs`|N/A| +|No|DEV|`lightweight-charts.development.mjs`|`lightweight-charts.development.cjs`|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`| + +⚠️ **Deprecation note:** CommonJS support will be removed from the library at the start of 2024. + +## Creating a chart + +Once the library has been installed in your repo you're ready to create your first chart. + +First of all, in a file where you would like to create a chart you need to import the library: + +```js +import { createChart } from 'lightweight-charts'; +``` + +[`createChart`](/api/index.md#createchart) is the entry-point for creating charts. You can use it to create as many charts as you need: + +```js +import { createChart } from 'lightweight-charts'; + +// ... + +// somewhere in your code +const firstChart = createChart(document.getElementById('firstContainer')); +const secondChart = createChart(document.getElementById('secondContainer')); +``` + +The result of this function is a [`IChartApi`](/api/interfaces/IChartApi.md) object, which you need to use to work with a chart instance. + +## Creating a series + +Once your chart is created it is ready to display data. + +The basic primitive to display a data is [a series](/api/interfaces/ISeriesApi.md). +There are different types of series: + +- Area +- Bar +- Baseline +- Candlestick +- Histogram +- Line + +To create a series with desired type you need to use appropriate method from [`IChartApi`](/api/interfaces/IChartApi.md). +All of them have the same naming `addSeries`, where `` is a type of a series you'd like to create: + +```js +import { createChart } from 'lightweight-charts'; + +const chart = createChart(container); + +const areaSeries = chart.addAreaSeries(); +const barSeries = chart.addBarSeries(); +const baselineSeries = chart.addBaselineSeries(); +// ... and so on +``` + +Please look at [this page](/series-types.md) for more information about different series types. + +Note that **a series cannot be transferred from one type to another one** since different series types have different data and options types. + +## Setting and updating a data + +Once your chart and series are created it's time to set data to the series. + +Note that regardless of the series type, the API calls are the same (the type of the data might be different though). + +### Setting the data to a series + +To set the data (or to replace all data items) to a series you need to use [`ISeriesApi.setData`](/api/interfaces/ISeriesApi.md#setdata) method: + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const areaSeries = chart.addAreaSeries({ + lineColor: LINE_LINE_COLOR, topColor: AREA_TOP_COLOR, + bottomColor: AREA_BOTTOM_COLOR, +}); +areaSeries.setData([ + { time: '2018-12-22', value: 32.51 }, + { time: '2018-12-23', value: 31.11 }, + { time: '2018-12-24', value: 27.02 }, + { time: '2018-12-25', value: 27.32 }, + { time: '2018-12-26', value: 25.17 }, + { time: '2018-12-27', value: 28.89 }, + { time: '2018-12-28', value: 25.46 }, + { time: '2018-12-29', value: 23.92 }, + { time: '2018-12-30', value: 22.68 }, + { time: '2018-12-31', value: 22.67 }, +]); + +const candlestickSeries = chart.addCandlestickSeries({ + upColor: BAR_UP_COLOR, downColor: BAR_DOWN_COLOR, borderVisible: false, + wickUpColor: BAR_UP_COLOR, wickDownColor: BAR_DOWN_COLOR, +}); +candlestickSeries.setData([ + { time: '2018-12-22', open: 75.16, high: 82.84, low: 36.16, close: 45.72 }, + { time: '2018-12-23', open: 45.12, high: 53.90, low: 45.12, close: 48.09 }, + { time: '2018-12-24', open: 60.71, high: 60.71, low: 53.39, close: 59.29 }, + { time: '2018-12-25', open: 68.26, high: 68.26, low: 59.04, close: 60.50 }, + { time: '2018-12-26', open: 67.71, high: 105.85, low: 66.67, close: 91.04 }, + { time: '2018-12-27', open: 91.04, high: 121.40, low: 82.70, close: 111.40 }, + { time: '2018-12-28', open: 111.51, high: 142.83, low: 103.34, close: 131.25 }, + { time: '2018-12-29', open: 131.33, high: 151.17, low: 77.68, close: 96.43 }, + { time: '2018-12-30', open: 106.33, high: 110.20, low: 90.39, close: 98.10 }, + { time: '2018-12-31', open: 109.87, high: 114.69, low: 85.66, close: 111.26 }, +]); + +chart.timeScale().fitContent(); +``` + +### Updating the data in a series + +In a case when your data is updated (e.g. real-time updates) you might want to update the chart as well. + +But using [`ISeriesApi.setData`](/api/interfaces/ISeriesApi.md#setdata) very often might affect the performance and we do not recommend to do this. +Also it replaces all series data with the new one, and probably this is not what you're looking for. + +Thus, to update the data you can use a method [`ISeriesApi.update`](/api/interfaces/ISeriesApi.md#update). +It allows you to update the last data item or add a new one much faster without affecting the performance: + +```js +import { createChart } from 'lightweight-charts'; + +const chart = createChart(container); + +const areaSeries = chart.addAreaSeries(); +areaSeries.setData([ + // ... other data items + { time: '2018-12-31', value: 22.67 }, +]); + +const candlestickSeries = chart.addCandlestickSeries(); +candlestickSeries.setData([ + // ... other data items + { time: '2018-12-31', open: 109.87, high: 114.69, low: 85.66, close: 111.26 }, +]); + +// sometime later + +// update the most recent bar +areaSeries.update({ time: '2018-12-31', value: 25 }); +candlestickSeries.update({ time: '2018-12-31', open: 109.87, high: 114.69, low: 85.66, close: 112 }); + +// creating the new bar +areaSeries.update({ time: '2019-01-01', value: 20 }); +candlestickSeries.update({ time: '2019-01-01', open: 112, high: 112, low: 100, close: 101 }); +``` diff --git a/website/versioned_docs/version-4.0/ios.md b/website/versioned_docs/version-4.0/ios.md new file mode 100644 index 0000000000..7f38d826ae --- /dev/null +++ b/website/versioned_docs/version-4.0/ios.md @@ -0,0 +1,100 @@ +--- +id: ios +description: You can use Lightweight Charts inside an iOS application. To use Lightweight Charts in that context, you can use our iOS wrapper, which will allow you to interact with lightweight charts library, which will be rendered in a web view. +keywords: + - charts + - iOS + - canvas + - charting library + - charting + - html5 charts + - financial charting library +sidebar_position: 6 +--- + +# iOS wrapper + +:::note +You can find the source code of the Lightweight Charts iOS wrapper in [this repository](https://github.com/tradingview/LightweightChartsIOS). +::: + +You can use Lightweight Charts inside an iOS application. To use Lightweight Charts in that context, you can use our iOS wrapper, which will allow you to interact with lightweight charts library, which will be rendered in a web view. + +## Installation + +:::info +Requires iOS 10.0+ +::: + +### CocoaPods + +[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate LightweightCharts into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +pod 'LightweightCharts', '~> 4.0.0' +``` + +### Swift Package Manager + +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. + +Once you have your Swift package set up, adding LightweightCharts as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. + +```swift +dependencies: [ + .package(url: "https://github.com/tradingview/LightweightChartsIOS", .upToNextMajor(from: "4.0.0")) +] +``` + +## Usage + +Once the library has been installed in your repo, you're ready to create your first chart. + +First of all, in a file where you would like to create a chart, you need to import the library: + +```swift +import LightweightCharts +``` + +Create instance of LightweightCharts, which is a subclass of UIView, and add it to your view. + +```swift +var chart: LightweightCharts! + +// ... +chart = LightweightCharts() +view.addSubview(chart) +// ... setup layout +``` + +Add any series to the chart and store a reference to it. + +```swift +var series: BarSeries! + +// ... +series = chart.addBarSeries(options: nil) +``` + +Add data to the series. + +```swift +let data = [ + BarData(time: .string("2018-10-19"), open: 180.34, high: 180.99, low: 178.57, close: 179.85), + BarData(time: .string("2018-10-22"), open: 180.82, high: 181.40, low: 177.56, close: 178.75), + BarData(time: .string("2018-10-23"), open: 175.77, high: 179.49, low: 175.44, close: 178.53), + BarData(time: .string("2018-10-24"), open: 178.58, high: 182.37, low: 176.31, close: 176.97), + BarData(time: .string("2018-10-25"), open: 177.52, high: 180.50, low: 176.83, close: 179.07) +] + +// ... +series.setData(data: data) +``` + +## How to run the provided example + +The [GitHub repository](https://github.com/tradingview/LightweightChartsIOS) for LightweightChartsIOS contains an example of the library in action. To run the example, start by cloning the repository, go to the _Example_ directory, and then run + +```sh +pod install +``` diff --git a/website/versioned_docs/version-4.0/migrations/_category_.yml b/website/versioned_docs/version-4.0/migrations/_category_.yml new file mode 100644 index 0000000000..d0d167eff0 --- /dev/null +++ b/website/versioned_docs/version-4.0/migrations/_category_.yml @@ -0,0 +1,2 @@ +label: "Migration guides" +position: 5 diff --git a/website/versioned_docs/version-4.0/migrations/from-v2-to-v3.md b/website/versioned_docs/version-4.0/migrations/from-v2-to-v3.md new file mode 100644 index 0000000000..e1ba5f3cbd --- /dev/null +++ b/website/versioned_docs/version-4.0/migrations/from-v2-to-v3.md @@ -0,0 +1,158 @@ +# 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](/api/interfaces/ITimeScaleApi.md) +(along with the new subscription methods [`ITimeScaleApi.subscribeVisibleLogicalRangeChange`](/api/interfaces/ITimeScaleApi.md#subscribevisiblelogicalrangechange) and [`ITimeScaleApi.unsubscribeVisibleLogicalRangeChange`](/api/interfaces/ITimeScaleApi.md#unsubscribevisiblelogicalrangechange)). + +So, to migrate your code to 3.0 you just need to replace: + +- `chart.subscribeVisibleTimeRangeChange` with `chart.timeScale().subscribeVisibleTimeRangeChange` +- `chart.unsubscribeVisibleTimeRangeChange` with `chart.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](../price-scale.md). + +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 + +```js +const chart = LightweightCharts.createChart(container, { + priceScale: { + position: 'left', + }, +}); +``` + +use + +```js +const chart = LightweightCharts.createChart(container, { + rightPriceScale: { + visible: false, + }, + leftPriceScale: { + visible: true, + }, +}); +``` + +then specify target price scale while creating a series: + +```js +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 + +```js +const chart = LightweightCharts.createChart(container, { + priceScale: { + position: 'none', + }, +}); +``` + +use + +```js +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 + +```js +const histogramSeries = chart.addHistogramSeries({ + overlay: true, +}); +``` + +use + +```js +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 + +```js +const chart = LightweightCharts.createChart(container); + +const mainSeries = chart.addLineSeries(); + +// ... + +chart.applyOptions({ + priceScale: { + position: 'left', + }, +}); +``` + +use + +```js +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. diff --git a/website/versioned_docs/version-4.0/migrations/from-v3-to-v4.md b/website/versioned_docs/version-4.0/migrations/from-v3-to-v4.md new file mode 100644 index 0000000000..d1424999f9 --- /dev/null +++ b/website/versioned_docs/version-4.0/migrations/from-v3-to-v4.md @@ -0,0 +1,200 @@ +# 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`](/api/enums/LastPriceAnimationMode.md) instead. + +## `scaleMargins` option has been removed from series options + +Previously, you could do something like the following: + +```js +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: + +```js +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`](/api/interfaces/LayoutOptions.md#background) property instead, e.g. instead of: + +```js +const chart = createChart({ + layout: { + backgroundColor: 'red', + }, +}); +``` + +use + +```js +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](./from-v2-to-v3.md#creating-overlay) where this option was deprecated. + +## `priceScale` option has been removed + +Please follow [the guide for migrating from v2 to v3](./from-v2-to-v3.md#two-price-scales). + +## `priceScale()` method of chart API now requires to provide price scale id + +Before v4 you could write the following code: + +```js +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'`: + +```js +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`. + +```js +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`](/api/interfaces/IChartApi.md#subscribeclick) (via [`MouseEventParams.time`](/api/interfaces/MouseEventParams.md#time)) +- [`IChartApi.subscribeCrosshairMove`](/api/interfaces/IChartApi.md#subscribecrosshairmove) (via [`MouseEventParams.time`](/api/interfaces/MouseEventParams.md#time)) +- [`LocalizationOptions.timeFormatter`](/api/interfaces/LocalizationOptions.md#timeformatter) (via argument of [`TimeFormatterFn`](/api/index.md#timeformatterfn)) +- [`TimeScaleOptions.tickMarkFormatter`](/api/interfaces/TimeScaleOptions.md#tickmarkformatter) (via argument of [`TickMarkFormatter`](/api/index.md#tickmarkformatter)) + +Previously the type of an inbound time (a values you provide to the library, e.g. in [`ISeriesApi.setData`](/api/interfaces/ISeriesApi.md#setdata)) was different from an outbound one (a values the library provides to your code, e.g. an argument of [`LocalizationOptions.timeFormatter`](/api/interfaces/LocalizationOptions.md#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`](/api/interfaces/ISeriesApi.md#setdata), you'll receive exactly the same value back: + +```js +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: + +```js +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: + +- [`IChartApi.subscribeClick`](/api/interfaces/IChartApi.md#subscribeclick) +- [`IChartApi.subscribeCrosshairMove`](/api/interfaces/IChartApi.md#subscribecrosshairmove) + +The property `seriesPrices` of [`MouseEventParams`](/api/interfaces/MouseEventParams.md) has been removed. + +Instead, you can use [`MouseEventParams.seriesData`](/api/interfaces/MouseEventParams.md#seriesdata) - it is pretty similar to the old `seriesPrices`, but it contains series' data items instead of just prices: + +```js +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`. + +```js +chart.subscribeCrosshairMove(param => { + console.log(param.hoveredObjectId); +}); + +chart.subscribeClick(param => { + console.log(param.hoveredObjectId); +}); +``` diff --git a/website/versioned_docs/version-4.0/price-scale.md b/website/versioned_docs/version-4.0/price-scale.md new file mode 100644 index 0000000000..64379464b8 --- /dev/null +++ b/website/versioned_docs/version-4.0/price-scale.md @@ -0,0 +1,40 @@ +--- +sidebar_position: 2 +--- + +# Price scale + +Price Scale (or price axis) is a vertical scale that mostly maps prices to coordinates and vice versa. +The rules of converting depend on a price scale mode, a height of the chart and visible part of the data. + +![Price scales](/img/price-scales.png "Price scales") + +By default, chart has 2 predefined price scales: `left` and `right`, and an unlimited number of overlay scales. + +Only `left` and `right` price scales could be displayed on the chart, all overlay scales are hidden. + +If you want to change `left` price scale, you need to use [`leftPriceScale`](/api/interfaces/ChartOptions.md#leftpricescale) option, to change `right` price scale use [`rightPriceScale`](/api/interfaces/ChartOptions.md#rightpricescale), to change default options for an overlay price scale use [`overlayPriceScales`](/api/interfaces/ChartOptions.md#overlaypricescales) option. + +Alternatively, you can use [`IChartApi.priceScale`](/api/interfaces/IChartApi.md#pricescale) method to get an API object of any price scale or [`ISeriesApi.priceScale`](/api/interfaces/ISeriesApi.md#pricescale) to get an API object of series' price scale (the price scale that the series is attached to). + +## Creating a price scale + +By default a chart has only 2 price scales: `left` and `right`. + +If you want to create an overlay price scale, you can simply assign [`priceScaleId`](/api/interfaces/SeriesOptionsCommon.md#pricescaleid) option to a series (note that a value should be differ from `left` and `right`) and a chart will automatically create an overlay price scale with provided ID. +If a price scale with such ID already exists then a series will be attached to this existing price scale. +Further you can use provided price scale ID to get its corresponding API object via [`IChartApi.priceScale`](/api/interfaces/IChartApi.md#pricescale) method. + +## Removing a price scale + +The default price scales (`left` and `right`) cannot be removed, you can only hide them by setting [`visible`](/api/interfaces/PriceScaleOptions.md#visible) option to `false`. + +An overlay price scale exists while there is at least 1 series attached to this price scale. +Thus, to remove an overlay price scale remove all series attached to this price scale. + + diff --git a/website/versioned_docs/version-4.0/series-types.md b/website/versioned_docs/version-4.0/series-types.md new file mode 100644 index 0000000000..7b5bee1173 --- /dev/null +++ b/website/versioned_docs/version-4.0/series-types.md @@ -0,0 +1,160 @@ +--- +sidebar_position: 1 +--- + +# Series types + +In this article you can read a brief overview of all supported series types. + +## A series customizations + +Any type of series can be customized and the set of available options that you can apply depends on a type of a series (see docs for each series type below). + +If you'd like to change any option of a series, you could do this in different ways: + +1. You can specify the default options while creating a series: + + ```js + // change default top & bottom colors of an area series in creating time + const series = chart.addAreaSeries({ + topColor: 'red', + bottomColor: 'green', + }); + ```` + + Note that every method to create a series has an optional `options` parameter. + +1. You can use [`ISeriesApi.applyOptions`](/api/interfaces/ISeriesApi.md#applyoptions) method to apply other options on the fly: + + ```js + // updating candlestick series options on the fly + candlestickSeries.applyOptions({ + upColor: 'red', + downColor: 'blue', + }); + ``` + +## Area + +- **Method to create**: [`IChartApi.addAreaSeries`](/api/interfaces/IChartApi.md#addareaseries) +- **Data format**: [`SingleValueData`](/api/interfaces/SingleValueData.md) or [`WhitespaceData`](/api/interfaces/WhitespaceData.md) +- **Style options**: a mix of [`SeriesOptionsCommon`](/api/interfaces/SeriesOptionsCommon.md) and [`AreaStyleOptions`](/api/interfaces/AreaStyleOptions.md) + +An area chart is basically a colored area between the line connecting all data points and [the time scale](./time-scale.md): + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const areaSeries = chart.addAreaSeries({ lineColor: LINE_LINE_COLOR, topColor: AREA_TOP_COLOR, bottomColor: AREA_BOTTOM_COLOR }); + +const data = [{ value: 0, time: 1642425322 }, { value: 8, time: 1642511722 }, { value: 10, time: 1642598122 }, { value: 20, time: 1642684522 }, { value: 3, time: 1642770922 }, { value: 43, time: 1642857322 }, { value: 41, time: 1642943722 }, { value: 43, time: 1643030122 }, { value: 56, time: 1643116522 }, { value: 46, time: 1643202922 }]; + +areaSeries.setData(data); + +chart.timeScale().fitContent(); +``` + +## Bar + +- **Method to create**: [`IChartApi.addBarSeries`](/api/interfaces/IChartApi.md#addbarseries) +- **Data format**: [`BarData`](/api/interfaces/BarData.md) or [`WhitespaceData`](/api/interfaces/WhitespaceData.md) +- **Style options**: a mix of [`SeriesOptionsCommon`](/api/interfaces/SeriesOptionsCommon.md) and [`BarStyleOptions`](/api/interfaces/BarStyleOptions.md) + +A bar chart shows price movements in the form of bars. + +Vertical line length of a bar is limited by the highest and lowest price values. +Open & Close values are represented by tick marks, on the left & right hand side of the bar respectively: + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const barSeries = chart.addBarSeries({ upColor: BAR_UP_COLOR, downColor: BAR_DOWN_COLOR }); + +const data = [{ open: 10, high: 10.63, low: 9.49, close: 9.55, time: 1642427876 }, { open: 9.55, high: 10.30, low: 9.42, close: 9.94, time: 1642514276 }, { open: 9.94, high: 10.17, low: 9.92, close: 9.78, time: 1642600676 }, { open: 9.78, high: 10.59, low: 9.18, close: 9.51, time: 1642687076 }, { open: 9.51, high: 10.46, low: 9.10, close: 10.17, time: 1642773476 }, { open: 10.17, high: 10.96, low: 10.16, close: 10.47, time: 1642859876 }, { open: 10.47, high: 11.39, low: 10.40, close: 10.81, time: 1642946276 }, { open: 10.81, high: 11.60, low: 10.30, close: 10.75, time: 1643032676 }, { open: 10.75, high: 11.60, low: 10.49, close: 10.93, time: 1643119076 }, { open: 10.93, high: 11.53, low: 10.76, close: 10.96, time: 1643205476 }]; + +barSeries.setData(data); + +chart.timeScale().fitContent(); +``` + +## Baseline + +- **Method to create**: [`IChartApi.addBaselineSeries`](/api/interfaces/IChartApi.md#addbaselineseries) +- **Data format**: [`SingleValueData`](/api/interfaces/SingleValueData.md) or [`WhitespaceData`](/api/interfaces/WhitespaceData.md) +- **Style options**: a mix of [`SeriesOptionsCommon`](/api/interfaces/SeriesOptionsCommon.md) and [`BaselineStyleOptions`](/api/interfaces/BaselineStyleOptions.md) + +A baseline is basically two colored areas (top and bottom) between the line connecting all data points and [the base value line](/api/interfaces/BaselineStyleOptions.md#basevalue): + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const baselineSeries = chart.addBaselineSeries({ baseValue: { type: 'price', price: 25 }, topLineColor: BASELINE_TOP_LINE_COLOR, topFillColor1: BASELINE_TOP_FILL_COLOR1, topFillColor2: BASELINE_TOP_FILL_COLOR2, bottomLineColor: BASELINE_BOTTOM_LINE_COLOR, bottomFillColor1: BASELINE_BOTTOM_FILL_COLOR1, bottomFillColor2: BASELINE_BOTTOM_FILL_COLOR2 }); + +const data = [{ value: 1, time: 1642425322 }, { value: 8, time: 1642511722 }, { value: 10, time: 1642598122 }, { value: 20, time: 1642684522 }, { value: 3, time: 1642770922 }, { value: 43, time: 1642857322 }, { value: 41, time: 1642943722 }, { value: 43, time: 1643030122 }, { value: 56, time: 1643116522 }, { value: 46, time: 1643202922 }]; + +baselineSeries.setData(data); + +chart.timeScale().fitContent(); +``` + +## Candlestick + +- **Method to create**: [`IChartApi.addCandlestickSeries`](/api/interfaces/IChartApi.md#addcandlestickseries) +- **Data format**: [`CandlestickData`](/api/interfaces/CandlestickData.md) or [`WhitespaceData`](/api/interfaces/WhitespaceData.md) +- **Style options**: a mix of [`SeriesOptionsCommon`](/api/interfaces/SeriesOptionsCommon.md) and [`CandlestickStyleOptions`](/api/interfaces/CandlestickStyleOptions.md) + +A candlestick chart shows price movements in the form of candlesticks. +On the candlestick chart, open & close values form a solid body of a candle while wicks show high & low values for a candlestick's time interval: + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const candlestickSeries = chart.addCandlestickSeries({ upColor: BAR_UP_COLOR, downColor: BAR_DOWN_COLOR, borderVisible: false, wickUpColor: BAR_UP_COLOR, wickDownColor: BAR_DOWN_COLOR }); + +const data = [{ open: 10, high: 10.63, low: 9.49, close: 9.55, time: 1642427876 }, { open: 9.55, high: 10.30, low: 9.42, close: 9.94, time: 1642514276 }, { open: 9.94, high: 10.17, low: 9.92, close: 9.78, time: 1642600676 }, { open: 9.78, high: 10.59, low: 9.18, close: 9.51, time: 1642687076 }, { open: 9.51, high: 10.46, low: 9.10, close: 10.17, time: 1642773476 }, { open: 10.17, high: 10.96, low: 10.16, close: 10.47, time: 1642859876 }, { open: 10.47, high: 11.39, low: 10.40, close: 10.81, time: 1642946276 }, { open: 10.81, high: 11.60, low: 10.30, close: 10.75, time: 1643032676 }, { open: 10.75, high: 11.60, low: 10.49, close: 10.93, time: 1643119076 }, { open: 10.93, high: 11.53, low: 10.76, close: 10.96, time: 1643205476 }]; + +candlestickSeries.setData(data); + +chart.timeScale().fitContent(); +``` + +## Histogram + +- **Method to create**: [`IChartApi.addHistogramSeries`](/api/interfaces/IChartApi.md#addhistogramseries) +- **Data format**: [`HistogramData`](/api/interfaces/HistogramData.md) or [`WhitespaceData`](/api/interfaces/WhitespaceData.md) +- **Style options**: a mix of [`SeriesOptionsCommon`](/api/interfaces/SeriesOptionsCommon.md) and [`HistogramStyleOptions`](/api/interfaces/HistogramStyleOptions.md) + +A histogram series is a graphical representation of the value distribution. +Histogram creates intervals (columns) and counts how many values fall into each column: + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const histogramSeries = chart.addHistogramSeries({ color: HISTOGRAM_COLOR }); + +const data = [{ value: 1, time: 1642425322 }, { value: 8, time: 1642511722 }, { value: 10, time: 1642598122 }, { value: 20, time: 1642684522 }, { value: 3, time: 1642770922, color: 'red' }, { value: 43, time: 1642857322 }, { value: 41, time: 1642943722, color: 'red' }, { value: 43, time: 1643030122 }, { value: 56, time: 1643116522 }, { value: 46, time: 1643202922, color: 'red' }]; + +histogramSeries.setData(data); + +chart.timeScale().fitContent(); +``` + +## Line + +- **Method to create**: [`IChartApi.addLineSeries`](/api/interfaces/IChartApi.md#addlineseries) +- **Data format**: [`LineData`](/api/interfaces/LineData.md) or [`WhitespaceData`](/api/interfaces/WhitespaceData.md) +- **Style options**: a mix of [`SeriesOptionsCommon`](/api/interfaces/SeriesOptionsCommon.md) and [`LineStyleOptions`](/api/interfaces/LineStyleOptions.md) + +A line chart is a type of chart that displays information as series of the data points connected by straight line segments: + +```js chart replaceThemeConstants +const chartOptions = { layout: { textColor: CHART_TEXT_COLOR, background: { type: 'solid', color: CHART_BACKGROUND_COLOR } } }; +const chart = createChart(document.getElementById('container'), chartOptions); +const lineSeries = chart.addLineSeries({ color: LINE_LINE_COLOR }); + +const data = [{ value: 0, time: 1642425322 }, { value: 8, time: 1642511722 }, { value: 10, time: 1642598122 }, { value: 20, time: 1642684522 }, { value: 3, time: 1642770922 }, { value: 43, time: 1642857322 }, { value: 41, time: 1642943722 }, { value: 43, time: 1643030122 }, { value: 56, time: 1643116522 }, { value: 46, time: 1643202922 }]; + +lineSeries.setData(data); + +chart.timeScale().fitContent(); +``` diff --git a/website/versioned_docs/version-4.0/time-scale.md b/website/versioned_docs/version-4.0/time-scale.md new file mode 100644 index 0000000000..78c8769157 --- /dev/null +++ b/website/versioned_docs/version-4.0/time-scale.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 3 +--- + +# Time scale + +Time scale (or time axis) is a horizontal scale at the bottom of the chart that displays the time of bars. + +![Time scale](/img/time-scale.png "Time scale") + +Time scale controls a current visible range, allows you to affect or change it, and can convert a time point or [an index](/api/index.md#logical) to a coordinate and vice versa (basically everything related to a x-scale of a chart). + +Also, it has a couple of events you can subscribe to to be notified when anything is happened. + +To work with time scale you can either change its options or use methods [ITimeScaleApi](/api/interfaces/ITimeScaleApi.md) which could be retrieved by using [`IChartApi.timeScale`](/api/interfaces/IChartApi.md#timescale) method. +All available options are declared in [TimeScaleOptions](/api/interfaces/TimeScaleOptions.md) interface. + +Note that you can apply options either via [`ITimeScaleApi.applyOptions`](/api/interfaces/ITimeScaleApi.md#applyoptions) or [`IChartApi.applyOptions`](/api/interfaces/IChartApi.md#applyoptions) with `timeScale` sub-object in passed options - these 2 approaches both have the same effect. + +## Logical range + +A [logical range](/api/index.md#logicalrange) is an object with 2 properties: `from` and `to`, which are numbers and represent logical indexes on the time scale. + +The starting point of the time scale's logical range is the first data item among all series. +Before that point all indexes are negative, starting from that point - positive. + +Indexes might have fractional parts, for instance `4.2`, due to the time-scale being continuous rather than discrete. + +Integer part of the logical index means index of the fully visible bar. +Thus, if we have `5.2` as the last visible logical index (`to` field), that means that the last visible bar has index 5, but we also have partially visible (for 20%) 6th bar. +Half (e.g. `1.5`, `3.5`, `10.5`) means exactly a middle of the bar. + +![Logical range](/img/logical-range.png "Logical range") + +Red vertical lines here are borders between bars. + +Thus, the visible logical range on the chart above is approximately from `-4.73` to `5.05`. diff --git a/website/versioned_docs/version-4.0/time-zones.md b/website/versioned_docs/version-4.0/time-zones.md new file mode 100644 index 0000000000..b017110512 --- /dev/null +++ b/website/versioned_docs/version-4.0/time-zones.md @@ -0,0 +1,114 @@ +--- +sidebar_position: 4 +--- +# Working with time zones + +This doc describes what do you need to do if you want to add time zone support to your chart. + +## Background + +By default, `lightweight-charts` doesn't support time zones of any kind, just because JavaScript doesn't have an API to do that. +Things that the library uses internally includes an API to: + +- Format a date +- Get a date and/or time parts of a date object (year, month, day, hours, etc) + +Out of the box we could rely on 2 APIs: + +- [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) +- [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) + +And even if to format a date we could (and we do) use `Date` object with its `toLocaleString` method (and we could even pass a `timeZone` field as an option), +but how about date/time field? + +All to solve this it seems that the only solution we have is `Date`'s getters, e.g. `getHours`. Here we could use 2 APIs: + +- UTC-based methods like `getUTCHours` to get the date/time in UTC +- Client-based methods like `getHours` to get the date/time in _a local (for the client)_ time zone + +As you can see we just unable to get date/time parts in desired time zone without using custom libraries (like `date-fns`) out of the box. + +Because of this we decided not to handle time zones in the library. The library treats all dates and times as UTC internally. + +But don't worry - it's easy to add time-zone support in your own code! + +## How to add time zone support to your chart + +**TL;DR** - time for every bar should be "corrected" by a time zone offset. + +The only way to do this is to change a time in your data. + +As soon as the library relies on UTC-based methods, you could change a time of your data item so in UTC it could be as it is in desired time zone. + +Let's consider an example. + +Lets say you have a bar with time `2021-01-01T10:00:00.000Z` (a string representation is just for better readability). +And you want to display your chart in `Europe/Moscow` time zone. + +According to tz database, for `Europe/Moscow` time zone a time offset at this time is `UTC+03:00`, i.e. +3 hours (pay attention that you cannot use the same offset all the time, because of DST and many other things!). + +By this means, the time for `Europe/Moscow` is `2021-01-01 13:00:00.000` (so basically you want to display this time over the UTC one). + +To display your chart in the `Europe/Moscow` time zone you would need to adjust the time of your data by +3 hours. So `2021-01-01T10:00:00.000Z` would become `2021-01-01T13:00:00.000Z`. + +Note that due a time zone offset the date could be changed as well (not only time part). + +This looks tricky, but hopefully you need to implement it once and then just forget this ever happened 😀 + +### `Date` solution + +One of possible solutions (and looks like the most simplest one) is to use approach from [this answer on StackOverflow](https://stackoverflow.com/a/54127122/3893439): + +```js +// you could use this function to convert all your times to required time zone +function timeToTz(originalTime, timeZone) { + const zonedDate = new Date(new Date(originalTime * 1000).toLocaleString('en-US', { timeZone })); + return zonedDate.getTime() / 1000; +} +``` + +#### Note about converting to a "local" time zone + +If you don't need to work with time zones in general, but only needs to support a client time zone (i.e. local), you could use the following trick: + +```js +function timeToLocal(originalTime) { + const d = new Date(originalTime * 1000); + return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()) / 1000; +} +``` + +### `date-fns-tz` solution + +You could also achieve the result by using [`date-fns-tz`](https://github.com/marnusw/date-fns-tz) library in the following way: + +```js +import { utcToZonedTime } from 'date-fns-tz'; + +function timeToTz(originalTime, timeZone) { + const zonedDate = utcToZonedTime(new Date(originalTime * 1000), timeZone); + return zonedDate.getTime() / 1000; +} +``` + +### `tzdata` solution + +If you have lots of data items and the performance of other solutions doesn't fit your requirements you could try to implement more complex solution by using raw [`tzdata`](https://www.npmjs.com/package/tzdata). + +The better performance could be achieved with this approach because: + +- you don't need to parse dates every time you want to get an offset so you could use [lowerbound algorithm](https://en.wikipedia.org/wiki/Upper_and_lower_bounds) (which is `O(log N)`) to find an offset of very first data point quickly +- after you found an offset, you go through all data items and check whether an offset should be changed or not to the next one (based on a time of the next time shift) + +## Why we didn't implement it in the library + +- `Date` solution is quite slow (in our tests it took more than 20 seconds for 100k points) +- Albeit `date-fns-tz` solution is a bit faster that the solution with `Date` but it is still very slow (~17-18 seconds for 100k points) and additionally it requires to add another set of dependencies to the package +- `tzdata` solution requires to increase the size of the library by [more than 31kB min.gz](https://bundlephobia.com/package/tzdata) (which is almost the size of the whole library!) + +Keep in mind that time zones feature is not an issue for everybody so this is up to you to decide whether you want/need to support it or not and so far we don't want to sacrifice performance/package size for everybody by this feature. + +## Note about converting business days + +If you're using a business day for your time (either [object](/api/interfaces/BusinessDay.md) or [string](api/index.md#time) representation), for example because of DWM nature of your data, +most likely you **shouldn't** convert that time to a zoned one, because this time represents a day. diff --git a/website/versioned_sidebars/version-4.0-sidebars.json b/website/versioned_sidebars/version-4.0-sidebars.json new file mode 100644 index 0000000000..0860cf013b --- /dev/null +++ b/website/versioned_sidebars/version-4.0-sidebars.json @@ -0,0 +1,33 @@ +{ + "docsSidebar": [ + "intro", + "series-types", + "price-scale", + "time-scale", + "time-zones", + { + "Migrations": [ + { + "type": "autogenerated", + "dirName": "migrations" + } + ] + }, + { + "type": "doc", + "id": "ios", + "label": "iOS" + }, + { + "type": "doc", + "id": "android", + "label": "Android" + } + ], + "apiSidebar": [ + { + "type": "autogenerated", + "dirName": "api" + } + ] +} diff --git a/website/versions.json b/website/versions.json index e2d64fc5df..632cb3a2fb 100644 --- a/website/versions.json +++ b/website/versions.json @@ -1,3 +1,4 @@ [ + "4.0", "3.8" ]