Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Baseline series should use min/max price range in visible range to calculate gradient stops #1005

Open
markeasting opened this issue Feb 11, 2022 · 10 comments · May be fixed by #1010
Open

Baseline series should use min/max price range in visible range to calculate gradient stops #1005

markeasting opened this issue Feb 11, 2022 · 10 comments · May be fixed by #1010
Assignees
Labels
breaking change Changes the API in a non backwards compatible way. enhancement Feature requests, and general improvements. help wanted Asking for outside help and/or contributions to this particular issue or PR.

Comments

@markeasting
Copy link

Lightweight Charts Version:
3.7.0

Steps/code to reproduce:

  • Add BaselineSeries
  • Set a custom price scale
  • Assign scaleMargins
var series = chart.addBaselineSeries({
  priceScaleId: 'my-custom-scale',
  scaleMargins: {
    top: 0.8,
    bottom: 0,
  },
  bottomFillColor2: 'rgba(0,0,0,1)',
  bottomFillColor1: 'rgba(0,0,0,0)',
  topFillColor2: 'rgba(0,0,0,0)',
  topFillColor1: 'rgba(0,0,0,1)',
  baseValue: { type: 'price', price: 180 },
});

Actual behavior:
The baseline gradient does not fully render the assigned color stop from the configuration.

Expected behavior:
The baseline gradient should use the scaleMargins to compute the color stops.

// src/renderers/baseline-renderer.ts:21
const gradient = ctx.createLinearGradient(0, 0, 0, data.bottom);

data.bottom should not be the height of the current chart, but the height of the series with the current scaleMargins.

Screenshots:
Expected here would be a full-black (#000000) top and bottom gradient.

Without scale margins:
image

Scale margins moved to top:
image

Scale margins moved to bottom:
image

CodeSandbox/JSFiddle/etc link:
https://jsfiddle.net/0r3cLmjd/51/

@timocov
Copy link
Contributor

timocov commented Feb 11, 2022

scaleMargins isn't supposed to be a part of the series, it is an option of the price scale (we're going to remove this property from series' options). Thus it looks like intended behaviour - the library uses the full width and height of the canvas to declare a gradient boundaries.

Could you please elaborate what do you want to achieve with that?

@markeasting
Copy link
Author

What I'd like to see is a consistent visual style for every BaselineSeries I add to my chart, wherever they are on the scale.

I currently have an upper and lower area for my 2 BaselineSeries, the top one looks different from the bottom one, even though the style options are the same.

In the meantime, I seem to have partially fixed it by adding a quick hack:

// baseline-pane-view.ts:renderer()

// Added lines
const baselineProps = this._series.options();
const t = (1 - baselineProps.scaleMargins.top) * height;
const b = (1 - baselineProps.scaleMargins.bottom) * height;

this._baselineAreaRenderer.setData({
  items: this._items,
  
  topFillColor1: baselineProps.topFillColor1,
  topFillColor2: baselineProps.topFillColor2,
  bottomFillColor1: baselineProps.bottomFillColor1,
  bottomFillColor2: baselineProps.bottomFillColor2,
  
  lineWidth: baselineProps.lineWidth,
  lineStyle: baselineProps.lineStyle,
  lineType: LineType.Simple,
  
  baseLevelCoordinate,
  top: t as Coordinate,		// Added line
  bottom: b as Coordinate,	// Added line
  
  visibleRange: this._itemsVisibleRange,
  barWidth,
});
// baseline-renderer.ts
protected override _fillStyle(ctx: CanvasRenderingContext2D): CanvasRenderingContext2D['fillStyle'] {
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  const data = this._data!;
  
  // New lines
  const gradient = ctx.createLinearGradient(0, data.top, 0, data.bottom);
  const base = data.baseLevelCoordinate - data.top;
  const h = data.bottom - data.top;
  const baselinePercent = clamp(base / h, 0, 1);
  
  gradient.addColorStop(0, data.topFillColor1);
  gradient.addColorStop(baselinePercent, data.topFillColor2);
  gradient.addColorStop(baselinePercent, data.bottomFillColor1);
  gradient.addColorStop(1, data.bottomFillColor2);
  
  return gradient;
}

Test before (notice lack of upper blue in lower chart and lack of purple in upper chart):
image

Test after:
image

As you can see, both series are now completely covered by their gradients as I would expect.

@timocov
Copy link
Contributor

timocov commented Feb 11, 2022

Have you tried your solution in the case when a price scale is manually scaled and you move the chart to vertically (especially out of your margins), how does it work?

@timocov
Copy link
Contributor

timocov commented Feb 11, 2022

Probably we need to provide a way to control what the start/end points should be. Right now we use the full height of the pane to paint it so I'm trying to understand what exact options we should have. As one of possible options could be max/min coordinates of a series for this visible range, but we'll need to check it properly.

@markeasting
Copy link
Author

I tried with the following code to change the price scale manually (series initialized without scale beforehand):

chart.priceScale('myscale').applyOptions({
    scaleMargins: {
        top: 0,
        bottom: 0.8
    },
});

Before:
image

After applying price scale options:
image

You can see that the gradient has changed, especially noticeable in the yellow area. And the purple on top became more purple (since it is now higher, closer to y=0)

@markeasting
Copy link
Author

Regarding your second comment, I think the most logical situation would be that the gradient is simply based on the min/max values of the series (or well, the top/bottom of the pane).

Having extra options for the start/end point in the API would seem cluttered, in my opinion 👍

@markeasting
Copy link
Author

Area series also seems to be affected.

One of the gradient color stops is not reached when using scaleMargins on its priceScale:

Without margins:
image

With margins:
image

Suddenly the upper side is not black anymore.

I have a fix for both of these issues, may I create a pull request?

@timocov
Copy link
Contributor

timocov commented Feb 14, 2022

You can see that the gradient has changed, especially noticeable in the yellow area. And the purple on top became more purple

Have you tried to move a series after that vertically? How the color is changing on this?

Having extra options for the start/end point in the API would seem cluttered, in my opinion

Hm, probably we need to have 2 separate hard-coded options here:

  • if a base value is percent (which is not supported right now, but we're keeping it in mind because it is available on tradingview.com in this way) then we should consider the whole height as a bottom value and 0 a top one
  • if a base value is price (this is the only available option right now) then we should use min/max values for bottom/top coordinates of a gradient.

What do you think about that @EastingAndNorthing?

I have a fix for both of these issues, may I create a pull request?

I'll discuss this question with the team and come back to you with the solution we could accept here.

@timocov timocov added enhancement Feature requests, and general improvements. need more feedback Requires more feedback. breaking change Changes the API in a non backwards compatible way. help wanted Asking for outside help and/or contributions to this particular issue or PR. and removed need more feedback Requires more feedback. labels Feb 14, 2022
@timocov
Copy link
Contributor

timocov commented Feb 14, 2022

Ok, it seems that we're happy with the solution you provided, i.e. calculate top/bottom based on the data in visible range instead of 0..height as it is right now. But this looks like a breaking changes so it is going to be released in the next major version v4.

@EastingAndNorthing Do you still want to create a pull request for that? See https://github.com/tradingview/lightweight-charts/blob/master/CONTRIBUTING.md#pull-requests for our contribution guide.

@timocov timocov changed the title Baseline series does not use scaleMargins to compute gradient Baseline series should use min/max price range in visible range to calculate gradient stops Feb 14, 2022
@markeasting
Copy link
Author

Have you tried to move a series after that vertically? How the color is changing on this?

Yes, this will give the same result, a color change while moving the chart up/down. See https://jsfiddle.net/ean9vj3r/1/

What do you think about that @EastingAndNorthing?

I agree, compared to the baseline series on Tradingview, it does seem more logical to use the entire scale as a gradient if we're talking about percentage values.

@EastingAndNorthing Do you still want to create a pull request for that?

Yes. I'll also add a few lines to check whether the base value is price, leaving the upcoming percentage scale at 0..height.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change Changes the API in a non backwards compatible way. enhancement Feature requests, and general improvements. help wanted Asking for outside help and/or contributions to this particular issue or PR.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants