lightweight-charts icon indicating copy to clipboard operation
lightweight-charts copied to clipboard

Implement basic box drawing

Open tpunt opened this issue 2 years ago • 51 comments

Type of PR: Enhancement

PR checklist:

  • [ ] Addresses an existing issue: fixes #
  • [ ] Includes tests
  • [ ] Documentation update

Overview of change:

I have implemented basic box/rectangle drawing. This feature has been requested a few times in the past (#706, #408, in online chatrooms, on discord, etc). I realise it has been discussed to expose the raw canvas also as a potential solution, but it seems there is some complexity around this (e.g. there are multiple canvases). It also feels as though basic features such as this (that complement the line drawing abilities) would be much better suited to be integrated into the library itself (which would also benefit from having the objects rescaled upon the rescaling of axes).

Things done:

  • Box creation based upon two prices and two times
  • Box moving with the rescaling of the axes
  • Box border (with colour, styling, thickness, and the ability to disable it)
  • Box fill colour with configurable opacity

Things remaining to do:

  • Ability to add a title to the box
  • Add prices to the Y axis for the top/bottom of the box
  • Add tests
  • Update the documentation

If this is desirable to have in the main project, then I am happy to spend some more time on finishing things up. If this is not desirable though, then I'll simply use my fork, and this PR can be closed.

Code example:

const box = {
  lowPrice: 2713.0,
  highPrice: 2797.0,
  earlyTime: 1641409200,
  lateTime: 1641823200,
  borderColor: '#00008B',
  borderWidth: 3,
  borderStyle: LightweightCharts.LineStyle.Dashed,
  fillColor: '#0ff',
  fillOpacity: 0.2,
  borderVisible: true,
  axisLabelVisible: false,
  title: 'My box',
};

const createdBox = mainSeries.createBox(box);

// mainSeries.removeBox(createdBox);
Example pictures Screenshot 2022-04-17 at 16 52 55

ezgif-2-4852b5dc20

Is there anything you'd like reviewers to focus on?

Whether this feature is desirable to have in the core library.

PR Update:

See https://github.com/tradingview/lightweight-charts/pull/1064#issuecomment-1304812364 of this PR for more abilities.

tpunt avatar Apr 17 '22 16:04 tpunt

That is a great feature! Is it hard to add an option to have the static width and scale only vertically when the chart is zoomed?

olablt avatar May 16 '22 17:05 olablt

It would be nice if this also takes in an array of boxes. Also what about being able to update the boxes? Currently if I am not mistaken you'll have to remove and re-add it again?

I suppose a unified api/template would be handy across all markers, boxes, etc... (Add, Remove, Bulk Add, Bulk Delete, Update)?

Swoorup avatar May 22 '22 14:05 Swoorup

That is a great feature! Is it hard to add an option to have the static width and scale only vertically when the chart is zoomed?

This could be added without much effort. I'm not quite sure what the use-case is for it, though (TradingView itself doesn't allow this either, unless I'm misunderstanding your comment).

tpunt avatar May 22 '22 20:05 tpunt

It would be nice if this also takes in an array of boxes. Also what about being able to update the boxes? Currently if I am not mistaken you'll have to remove and re-add it again?

I suppose a unified api/template would be handy across all markers, boxes, etc... (Add, Remove, Bulk Add, Bulk Delete, Update)?

Yes, I'm not against adding any of these abilities. This PR only adds a very basic box drawing API that is supposed to mimic the pre-existing line drawing API. I'm happy to expand upon this if the maintainers would like this apart of the main repo. Otherwise, the box API in its current state is enough for my own private project needs, so I'll just close this PR.

tpunt avatar May 22 '22 20:05 tpunt

For those looking to use this feature, I had to do a couple of extra things in order to integrate this into my own project via NPM:

  1. Add a prepare command to have node build the project upon installation (since the git repo doesn't have these files): change
  2. Remove the install hooks around git: change

I did both of these in my boxes-install branch, so for those looking to use this, they can simply execute the following:

npm install "https://github.com/tpunt/lightweight-charts.git#boxes-install"

tpunt avatar May 22 '22 20:05 tpunt

@tpunt can you add createBoxes api in it?

leosj avatar Jul 07 '22 10:07 leosj

@leosj I'm happy to extend the API, but only if this feature gets added to this repo. I'm still waiting for the owners here to comment on this PR - right now, it looks as though they are not interested in adding new features to lightweight-charts. This is a shame because the charting library is excellent, but it really lacks some quite basic, but very useful abilities.

tpunt avatar Jul 26 '22 12:07 tpunt

https://user-images.githubusercontent.com/101854573/181699967-9db4dc72-7c4b-497e-a229-887e098a081a.mp4

It seems that the box disappears completely when the height of the box exceeds the visible y-axis scale.

X-axis scale works fine. Any hints on how to make the box show even if the visible y-axis is not inclusive of the height of the box?

Attached video to illustrate what I mean.

Edit: nvm I mixed up the lowPrice and highPrice in the box settings. It is working fine

ty11111111 avatar Jul 29 '22 06:07 ty11111111

This works perfectly and is the unique feature I was requiring from Lightweight Charts. Thanks a ton for your work !!

GorillaBus avatar Oct 05 '22 17:10 GorillaBus

This is great. Just what i was looking for!

Is it possible for someone to provide a method of including this in HTML such as

https://jsfiddle.net/adrianntf/6qea5ytv/

That would be great. Thanks

juniormcmillan avatar Oct 24 '22 10:10 juniormcmillan

@juniormcmillan I'm not sure I understand why you'd want the ability to write HTML code, and have that display boxes on the chart. You could write JSON code to generate both HTML code and boxes, though.

tpunt avatar Nov 06 '22 13:11 tpunt

Update

I've made an update to this PR. I wanted the ability to draw boxes that were rotated, but it appears that canvas does not allow you to draw boxes in that way. You can draw a simple box and then rotate it, but that would not scale properly with the axes on the chart. So instead of making a box a canvas rectangle, I've made it a series of connecting lines (which should have no functional change).

To take advantage of this new flexibility to draw arbitrary shapes, you can specify a list of corners (2 or more), rather than the old parameters lowPrice, highPrice, earlyTime, lateTime.

This is fully backwards compatible with the original PR (for those already relying upon it). Examples:

Diagonal box example
const box = {
        corners: [
                { time: 1641392200, price: 2902 },
                { time: 1641324200, price: 2902 },
                { time: 1641412200, price: 2750 },
                { time: 1641425200, price: 2750 },
        ],
        borderColor: '#00f',
        borderWidth: 3,
        borderStyle: LightweightCharts.LineStyle.Dashed,
        fillColor: '#0ff',
        fillOpacity: 0.3,
        borderVisible: true,
        axisLabelVisible: false,
        title: 'My box',
};

const createdBox = mainSeries.createBox(box);

// mainSeries.removeBox(createdBox);

Picture: Screen Recording 2022-11-06 at 14 04 53

Arbitrary lines

Creating horizontal, vertical, and diagonal lines (of set lengths):

const shapes = [{
        corners: [
                { time: 1641392200, price: 2902 },
                { time: 1641412200, price: 2750 },
        ],
        borderColor: '#fff',
        borderWidth: 2,
        borderStyle: LightweightCharts.LineStyle.Dashed,
        fillColor: '#fff',
        fillOpacity: 0.3,
        borderVisible: true,
        axisLabelVisible: false,
        title: 'My box',
},{
        corners: [
                { time: 1641272200, price: 2875 },
                { time: 1641512200, price: 2875 },
        ],
        borderColor: '#fff',
        borderWidth: 2,
        borderStyle: LightweightCharts.LineStyle.Dashed,
        fillColor: '#fff',
        fillOpacity: 0.3,
        borderVisible: true,
        axisLabelVisible: false,
        title: 'My box',
},{
        corners: [
                { time: 1641812200, price: 2700 },
                { time: 1641812200, price: 2900 },
        ],
        borderColor: '#fff',
        borderWidth: 2,
        borderStyle: LightweightCharts.LineStyle.Dashed,
        fillColor: '#fff',
        fillOpacity: 0.3,
        borderVisible: true,
        axisLabelVisible: false,
        title: 'My box',
}];

for (shape of shapes) {
        const createdShape = mainSeries.createBox(shape);
        // mainSeries.removeBox(createdShape);
}

Picture: Screenshot 2022-11-06 at 14 15 57

I realise the createBox name is now a bit of a misnomer - createShape would be more accurate. However, I'll leave it as-is to maintain backwards compatibility for others.

Changes are apart of the boxes and boxes-install branches, for those looking to use this.

tpunt avatar Nov 06 '22 14:11 tpunt

I haven't tried your updated code yet but from looking at it, am I correct in assuming that you can have more than 4 corners ?

0x0tyy avatar Nov 08 '22 10:11 0x0tyy

@0x0tyy Yes, you can specify 2 or more corners. 2 corners just means a straight line (in any direction).

tpunt avatar Nov 09 '22 12:11 tpunt

Ive tried everything possible to disable the border and its still showing. Any clues what i did wrong?

Capture

image

mrle0pold avatar Dec 10 '22 08:12 mrle0pold

i tried to use this patch to create a kernel density estimated TPO market profile. Unfortunately, even after decreasing the tick size (to 1 , instead of 0.01), performance still drops after 2-3 profiles on screen. I could decrease tick size further and overcome the jagged lines with beziercurves but I don't think it will make a huge difference. Anyone have any other suggestions for increasing performance?

https://user-images.githubusercontent.com/108040259/207564608-c83bfd05-47f3-4bc1-9373-a40cd9b90095.mp4

0x0tyy avatar Dec 14 '22 10:12 0x0tyy

@mrle0pold Good catch! When I moved things to line-based drawing, the default border was a thin black line. I've now made a commit (6aa61f8354acaad725cc68e65cb26e43ef8e5999) to allow you to (once again) disable the border completely (borderVisible: false).

tpunt avatar Dec 18 '22 17:12 tpunt

@0x0tyy I assume it is because of the number of points needing to be drawn in order to render such shapes. Would it be possible to render bars instead of curves (similar to other Volume Profile indicators on TradingView)? They would be much friendlier, since there will be far fewer points.

tpunt avatar Dec 18 '22 17:12 tpunt

Really cool opportunity! Please release it!

WISEPLAT avatar Feb 19 '23 09:02 WISEPLAT

I was getting compile errors when taking the latest version of Light-weight charts with this code. Have fixed them and raised a PR in the form - https://github.com/cheriansk/lightweight-charts/pull/1

cheriansk avatar Mar 04 '23 22:03 cheriansk

Thank you @cheriansk for the commit, I ended up adding tpunt's changes for the package.json https://github.com/tradingview/lightweight-charts/pull/1064#issuecomment-1133973572 so that I can install the library with npm using the following command (just in case if someone else needs it):

npm install "https://github.com/sharpkids/lightweight-charts.git"

sharpkids avatar Mar 05 '23 01:03 sharpkids

I've now rebased this branch against the latest master changes (commit: 1760f5a4a82eaded3a06340d4a3ec139c5ab1b38). They have also been applied to my boxes-install branch.

tpunt avatar Mar 31 '23 13:03 tpunt

I've now rebased this branch against the latest master changes (commit: 1760f5a). They have also been applied to my boxes-install branch.

I hope this makes it to prod someday!

Creative-Difficulty avatar Mar 31 '23 13:03 Creative-Difficulty

I hope this makes it to prod someday!

Either that, or we get a solid plugin system that allows for this and similar things to be implemented elegantly. It's a bit of a pain right now because there's so much boilerplate code involved and exposure to core implementation details. We'll have to see how #1238 goes, I guess.

tpunt avatar Mar 31 '23 14:03 tpunt

is there any plans of merging this and pushing to prod? and/or make it compatible with 4.0.1?

thanks!

mattou78400 avatar May 01 '23 08:05 mattou78400

We'll soon release a plugin mechanism on top of the library that will allow you to achieve that request without necessarily awaiting for our approval. Will update this ticket once we have something more concrete.

romfrancois avatar May 02 '23 09:05 romfrancois

@mattou78400 This PR is already compatible with 4.0.1 - I rebased it against the master branch a month ago or so.

tpunt avatar May 04 '23 12:05 tpunt

Hii , Is possible to draw box outside xAxis?

Like this : image

Thank you cc : @tpunt

erfinbadrian avatar May 09 '23 01:05 erfinbadrian

@erfinbadrian Hey Erfin.

In the current branch, no, this is not possible. However, I had the exact same need, and so I implemented this in a boxes-offscreen branch. Note that in order to get things to work, you must pass in a timeframe parameter. This is because lightweight-charts has no concept of a timeframe when rendering candlesticks - it simply renders the OHLC objects you give it. This means you can technically pass in 3 minute candles with 15 minute candles (with 4 hour candles, etc) and the chart will render fine. In reality, this makes no sense. So in order to correctly calculate the distance offsceen, you need to pass in a timeframe parameter (a number in seconds) with the box options.

Note that the boxes-offscreen branch does not include the two commits from boxes-install (4a74c7d7188d511199c64adf18a7ea4e7b942328, 8c3f8b0b828c2dc340f061ac499ff21a49010a4d), so you may want to cherry-pick them for a smoother npm install experience.

tpunt avatar May 12 '23 10:05 tpunt

can you please share the built branch with us? because im getting so confused with the errors when i try to build it myself

LmfaoHax avatar May 18 '23 12:05 LmfaoHax