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

Rewrite filler #6795

Merged
merged 9 commits into from
Dec 31, 2019
Merged

Rewrite filler #6795

merged 9 commits into from
Dec 31, 2019

Conversation

kurkle
Copy link
Member

@kurkle kurkle commented Nov 30, 2019

After implementing fastPath, I realized most of the drawing logic is duplicated in filler.
There I thought, exposing the path drawing part from Line would allow using it in filler and make it much simpler. It turned out not to be as simple as I thought.

Current implementation in master, fills based point on index in the data array. With most of the index bound stuff removed elsewhere, I think its good to do it here too. So I needed to add interpolate to Line to allow fill targeting between points. I imagine that functionality will be welcomed by the community (crosshairs, tooltips, getting the value under mouse etc)

Some fixtures needed to be updates, because master's fill and border don't agree on all aspects. For example, a radar with tension and missing points, border is drawn as straight line for the missing part, while fill follows the spline. Some filling bugs are also resolved.

So examples, config:

            datasets: [{
                backgroundColor: rgba(0, 0, 192, 0.25),
                borderColor: rgba(0, 0, 192, 0.75),
                data: [{x: 1, y: 5},{x:5, y: 2},{x:8, y:-3}],
                fill: false
            }, {
                backgroundColor: rgba(128, 0, 128, 0.25),
                borderColor: rgba(128, 0, 128, 0.75),
                data: [{x: NaN, y: NaN}, {x: 2, y: 3}, {x:6.5, y: 7}],
                fill: '-1'
            }]

Master:
image

PR:
image

Copy link
Contributor

@benmccann benmccann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh. This is a big one. And I've never used the filler or interpolation, so not sure how much I'll really be able to help reviewing, but I'll see if I have some time later

most of the drawing logic is duplicated in filler

I'm surprised there's more code after this change since the original motivation was duplicated code :-)

y: y,
x,
y,
r,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be helpful to add some comments explaining the difference between r, radius, and hitRadius and why each is needed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that the r is renamed to angle, do you still need clarification between radius and hitRadius?

Copy link
Member

@etimberg etimberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't get fully through this yet, but a few comments

src/controllers/controller.radar.js Outdated Show resolved Hide resolved
src/helpers/helpers.math.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
@kurkle kurkle force-pushed the filler-rewrite branch 3 times, most recently from c97c694 to 4d9fded Compare December 8, 2019 10:40
@kurkle
Copy link
Member Author

kurkle commented Dec 8, 2019

Another example

type: 'radar',
data: {
    datasets: [{
        backgroundColor: 'rgba(255, 0, 0, 0.25)',
        borderColor: 'rgba(255, 0, 0, 0.75)',
        data: [1,1,1,1,1,1,1,1,1],
        fill: true
    }, {
        backgroundColor: 'rgba(0, 255, 0, 0.25)',
        borderColor: 'rgba(0, 255, 0, 0.75)',
        data: [2,2,null,2,2,2,2,null,2],
        fill: '-1'
    }, {
        backgroundColor: 'rgba(0, 0, 255, 0.25)',
        borderColor: 'rgba(0, 0, 255, 0.75)',
        data: [3,3,3,3,3,3,3,3,3],
        fill: '-1'
    }, {
        backgroundColor: 'rgba(255, 0, 255, 0.25)',
        borderColor: 'rgba(255, 0, 255, 0.75)',
        data: [4,4,4,4,4,4],
        fill: '-1'
    }, {
        backgroundColor: 'rgba(0, 255, 255, 0.25)',
        borderColor: 'rgba(0, 255, 255, 0.75)',
        data: [5,5,null,null,5,5,5,5,5],
        fill: '-1'

    }],
    labels: ['label1', 'label2', 'label3', 'label4', 'label5', 'label6', 'label7', 'label8', 'label9']
},
options: {
    spanGaps: false,
    responsive: false,
    scale: {min: 0, display: false},
    elements: {
        line: {
            tension: 0.6
        }
    }
}

Master:
image

PR:
image

Turn spanGaps: true

Master:
image

PR:
image

@kurkle kurkle marked this pull request as ready for review December 8, 2019 11:12
@etimberg
Copy link
Member

etimberg commented Dec 8, 2019

I had a read. I like the fixes and I think I understand how this all works. @benmccann what do you think?

@kurkle
Copy link
Member Author

kurkle commented Dec 8, 2019

Just few comments on the update: line is now split in segments (split on line brreaks)
When fill is applied between two lines, segments are compared each matching segments on both lines is a new 'fill segment' those ard then pathed around an filled.
This is somewhat harder on radial lines, because of the looping. Radial segments are matched using angles (radians). I used r to match the axis radial scale uses. That could be changed ofc, but I did not want to grow this any more.

@kurkle kurkle changed the title WIP: Rewrite filler Rewrite filler Dec 9, 2019
src/controllers/controller.radar.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
src/helpers/helpers.math.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
Copy link
Member Author

@kurkle kurkle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benmccann couple of places, where the angle stored in r is used.

src/elements/element.line.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
src/elements/element.line.js Outdated Show resolved Hide resolved
Copy link
Contributor

@benmccann benmccann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a heads up that this needs to be rebased

@kurkle
Copy link
Member Author

kurkle commented Dec 19, 2019

Rebased and made some adjustments based on reviews. Ready for next round.

@kurkle
Copy link
Member Author

kurkle commented Dec 19, 2019

Last one fixes the issue described in #6838 comments.
Added a test to catch that too.
Demo

const {points, _view: vm} = line;
const lineMethod = getLineMethod(vm);
const count = points.length;
let {move = true, reverse} = options || {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move can't be specified in the options, can it? If that's the case, I think it'd make that clearer to declare it on its own line

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can and is, from filler.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it documented anywhere? I didn't see it on https://www.chartjs.org/docs/latest/charts/area.html. Could we add it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, there is a misunderstanding here. Maybe I should rename options to args here, these are just options passed to the function, not user provided.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying. Yeah, args or params or something else would be good

etimberg
etimberg previously approved these changes Dec 25, 2019
etimberg
etimberg previously approved these changes Dec 28, 2019
if (!prev.skip) {
last = start;
}
for (end = start + 1; end < max; ++end) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this impact the uPlot benchmark? It looks like we now have to loop over all data points an additional time and I'm worried that might be expensive

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconclusive. uPlot bench uses fastPath that skips this segment stuff.

Heres a plunker with some preconfigured uPlot based benchmarks to check it out:
https://plnkr.co/edit/QJ9IMuiybyXWHtgdTfEK?p=preview

@kurkle
Copy link
Member Author

kurkle commented Dec 28, 2019

Fixed a bug in interpolated filling and added a test to catch it. Same test in plunker

src/elements/element.line.js Show resolved Hide resolved
}

if (useFastPath(options)) {
fastPath(ctx, points, spanGaps);
if (!loop && useFastPath(options, params)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should loop just be a parameter to useFastPath? if we make it an instance method then you wouldn't have to pass in loop or options

@kurkle
Copy link
Member Author

kurkle commented Dec 29, 2019

Yet another update to this.

  • fastPath (or fastPathSegment as its named now) is enabled for fill.
  • Segment stuff moved to helpers.segment to make things a bit cleaner.
  • Bezier stuff moved to helpers.curve.
  • segments are now computed for fastPath too. snapGaps: true disables the segmentation. Added that to performance.md

Plunker

Quick average seems like its about 25% faster when fill is enabled. Other modes are roughly the same (GC causes a lot of variation, so its hard to compare).

benmccann
benmccann previously approved these changes Dec 30, 2019
src/helpers/helpers.curve.js Outdated Show resolved Hide resolved
@etimberg etimberg merged commit 102a311 into chartjs:master Dec 31, 2019
@kurkle kurkle deleted the filler-rewrite branch February 19, 2020 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants