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

Create a new hook to enable data decimation #8255

Merged
merged 22 commits into from Feb 1, 2021

Conversation

etimberg
Copy link
Member

@etimberg etimberg commented Dec 30, 2020

The beforeElementsUpdate hook can be used to decimate data. The chart elements will not be created until after this hook has fired ensuring that if decimation occurs, only the needed elements will be created.

This is a simpler take on #8251 that does not need to reorder any passes. Instead, the decimation plugin uses a heuristic to determine the chart width.

Results

Test 1 (uPlot Benchmark, 100 runs)

Master PR
Average 53ms 20 ms
Min 37ms 13 ms
Max 175ms 137ms
Variation 138ms 124ms
Heap 36425.8 kB 21191.4 kB

Test 2 (10M data points, since run)

Master PR
Render Time 2954.39 ms 153.13 ms

Decimation Plugin

{
	id: 'decimate-data',
	beforeElementUpdate: (chart, args) => {
		// Use an approximation since this is before scales are parsed
		const verticalAxisCount = Object.values(chart.scales).reduce((acc, scale) => acc += scale.axis === 'y' ? 1 : 0, 0);

		// assume ~50px for now. If the axis is actually wider then we have more points than needed
		// TODO: Take display settings into account and compute a more accurate guess for each axis
		const availableWidth = chart.width - (verticalAxisCount * 50);

		chart.data.datasets.forEach((dataset, datasetIndex) => {
			let i, point, x, y, prevX, minIndex, maxIndex, minY, maxY;
			const {data} = dataset;
			const meta = chart.getDatasetMeta(datasetIndex);

			if (meta.type !== 'line') {
				// Only line datasets are supported
				return;
			}

			const xAxis = chart.scales[meta.xAxisID];
			if (xAxis.type !== 'linear' && xAxis.type != 'time') {
				// Only linear interpolation is supported
				return;
			}

			if (!!chart.options.parsing) {
				// Plugin only supports data that does not need parsing
				return;
			}

			const decimated = [];

			const xMin = data[0].x;
			const xMax = data[data.length - 1].x;
			const dx = xMax - xMin;

			for (i = 0; i < data.length; ++i) {
				point = data[i]
				x = (point.x - xMin) / dx * availableWidth;
				y = point.y;
				const truncX = x | 0;

				if (truncX === prevX) {
					// Determine `minY` / `maxY` and `avgX` while we stay within same x-position
					if (y < minY) {
						minY = y;
						minIndex = i;
					} else if (y > maxY) {
						maxY = y;
						maxIndex = i;
					}
				} else {
					// Push up to 4 points, 3 for the last interval and the first point for this interval
					if (minIndex && maxIndex) {
						decimated.push(data[minIndex], data[maxIndex]);
					}
					if (i > 0) {
						// Last point in the previous interval
						decimated.push(data[i - 1]);
					}
					decimated.push(point);
					prevX = truncX;
					minY = maxY = y;
					minIndex = maxIndex = i;
				}
			}

			dataset._data = dataset.data;
			dataset.data = decimated;
		});
	}
};

@benmccann
Copy link
Contributor

I'm not quite sure how to read the results. Does that mean it went from 2086ms to 1487ms + 153ms or just 153ms? Good improvement either way, but if the latter then wow!!

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.

I'm assuming if we had this new plugin, then we wouldn't get benefit from the existing line controller decimation anymore? I wonder if we removed the existing line controller decimation and added this general decimation plugin if we'd stay roughly equal in size, but come out ahead on speed and so maybe we should include this plugin in core in that case

src/core/core.controller.js Outdated Show resolved Hide resolved
src/core/core.controller.js Show resolved Hide resolved
src/core/core.datasetController.js Show resolved Hide resolved
types/index.esm.d.ts Outdated Show resolved Hide resolved
@etimberg
Copy link
Member Author

I've updated that to be clearer. It's two different tests. On the main benchmark it went, on average over 100 runs, from 53ms to 20ms. Rendering 10M points, rendering time dropped from 2954ms to 153ms

@etimberg
Copy link
Member Author

I'm assuming if we had this new plugin, then we wouldn't get benefit from the existing line controller decimation anymore? I wonder if we removed the existing line controller decimation and added this general decimation plugin if we'd stay roughly equal in size, but come out ahead on speed and so maybe we should include this plugin in core in that case

@kurkle and I bounced that around too. It might be worth exploring since this also reduces memory overhead. That being said, without the plugin this is quite small.

Size Change: +152 B (0%)

Total Size: 217 kB

Filename Size Change
dist/chart.esm.js 63.1 kB +56 B (0%)
dist/chart.js 79 kB +59 B (0%)
dist/chart.min.js 57.3 kB +37 B (0%)

@leeoniya
Copy link

leeoniya commented Dec 31, 2020

+1 for having this behavior in the core and enabled via an opt, or better yet on by default.

i'm already not a fan of HighCharts needing the additional "boost" module either. at some point i'm going to add ** callouts for libs that require excessive and precise config to attain the shown bench results.

@etimberg
Copy link
Member Author

etimberg commented Dec 31, 2020

That's some good feedback @leeoniya. I agree that if we can find a way to make it on by default, it'd be great. In my ideal world, I'd try to make it enabled even when we have to parse and sort the data as it would be a good improvement for everyone. With that said, I did look at flot and they have the hook for decimation before parsing.

Some things I'd want to do on the plugin before we consider shipping it:

  • Support more axis types (log, timeseries)
  • Bail out early if data.length < 4 * width
  • Testing for heuristics and decide if fancier axis measuring is needed
  • Disable when the primary axis is y
  • Find a way to make this work better with editable data. Right now replaced dataset.data is disruptive

Copy link
Member

@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.

I think these new hook(s) could be valuable even if we do the decimation in core.

If doing in core (+1), it might be good to just have that new hook for controllers too, and implement it in the line controller. Does not make sense to have it in 2 levels, so moving from LineElement to LineController works for me.

Note: After this, the addElements only adds the dataset element, which is not what you'd except from the function name.

Comment on lines 416 to 421
let i, parsed, cur, prev;

if (start > 0) {
if (start > 0 || (start === 0 && count < data.length)) {
sorted = meta._sorted;
prev = meta._parsed[start - 1];
prev = start > 0 ? meta._parsed[start - 1] : undefined;
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let i, parsed, cur, prev;
if (start > 0) {
if (start > 0 || (start === 0 && count < data.length)) {
sorted = meta._sorted;
prev = meta._parsed[start - 1];
prev = start > 0 ? meta._parsed[start - 1] : undefined;
}
let sorted = start === 0 && count === data.length ? true : meta._sorted;
let prev = start > 0 && meta._parsed[start - 1];
let i, cur, parsed;

Copy link
Member Author

Choose a reason for hiding this comment

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

Good simplification. With fresh eyes, I thought of some cases where this method could incorrectly detect the sorted status of the data array.

Incorrectly Mark Data as not Sorted

const data = [0, 2, 1, 3, 4];
parse(0, 5); // not sorted

data[1] = 1;
data[2] = 2; // data == [0, 1, 2, 3, 4]

parse(0, 3); // not sorted

Incorrect Mark Data as Sorted

const data = [0, 1, 2, 3, 4];
parse(0, 5); // sorted

data[2] = 4; // data == [0, 1, 4, 3, 4]
parse(0, 3); // sorted

Copy link
Member

Choose a reason for hiding this comment

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

Good points. We should set the meta._sorted to false when data is modified (and parsing is enabled).
And add tests for these cases, to make sure it works :)

src/core/core.controller.js Outdated Show resolved Hide resolved
@etimberg
Copy link
Member Author

I think these new hook(s) could be valuable even if we do the decimation in core.

If doing in core (+1), it might be good to just have that new hook for controllers too, and implement it in the line controller. Does not make sense to have it in 2 levels, so moving from LineElement to LineController works for me.

Note: After this, the addElements only adds the dataset element, which is not what you'd except from the function name.

Can you expand a bit on what you're thinking for this? Do you mean having a beforeElementUpdate method on the controller that gets called first? Or do you mean a beforeElementUpdate hook that the dataset controller fires?

@kurkle
Copy link
Member

kurkle commented Dec 31, 2020

Can you expand a bit on what you're thinking for this? Do you mean having a beforeElementUpdate method on the controller that gets called first? Or do you mean a beforeElementUpdate hook that the dataset controller fires?

The first one, having a beforeElementsUpdate on the controller. I did not walk the code through, so not sure if that makes sense.

@etimberg
Copy link
Member Author

It might be possible to put it there though not sure if the controller should be modifying the data.

@etimberg
Copy link
Member Author

etimberg commented Dec 31, 2020

I made some progress. I added the plugin into the core (not yet enabled by default). I also added a new feature, dataset.dataKey that allows pointing the data stream away from dataset.data. My thinking is that users don't want their original array modified, so the decimation plugin stores the decimated data as dataset._decimated and then we tell the controller to treat datset._decimated as the array to listen to (for updates, etc). That should resolve a lot of the complexity with updates & user interactions.

Work Still To-Do

  • Document decimation plugin options
  • Test all controllers with dataKey feature
  • Decide on some initial options for decimation. Allow code to support configurable decimation algorithms in the future

types/index.esm.d.ts Outdated Show resolved Hide resolved
@benmccann
Copy link
Contributor

dataKey seems a little risky to me because every plugin, etc. would have to understand to get data from dataKey instead of data which would add complication. I'd probably just stick the original data on another field called _originalData and replace data with the decimated data. The original array isn't be modified (just moved), so the user can easily maintain a reference to it outside the chart to maintain access to it without having to know about the _originalData field.

@kurkle
Copy link
Member

kurkle commented Jan 2, 2021

We could create a getter for the data that uses dataKey. Would need to rename the original data property then to something else and default dataKey to that.

@etimberg
Copy link
Member Author

etimberg commented Jan 2, 2021

I thought about the getter solution too. The reason I didn't implement it was what happens if someone did something like #7340 and passed the data in a class instance

@benmccann benmccann linked an issue Jan 3, 2021 that may be closed by this pull request
@benmccann
Copy link
Contributor

I'm not sure I understand how the class instance relates to having a getter. They seem orthogonal to me, but I might be missing something

@etimberg
Copy link
Member Author

etimberg commented Jan 3, 2021

I meant if the user passes in a class where data is already a getter, we may not be able to redefine it. This is also likely a problem for frozen data objects (hence why we moved the metas to chart._metasets). Perhaps we can put the data key there, or as you said, just modify the data array and tell the user that that's how the plugin works.

@kurkle @simonbrunel any thoughts?

@kurkle
Copy link
Member

kurkle commented Jan 4, 2021

The use passed data object can be stored in the config. we can build the chart.data.datasets[i] and have getter for that objects data property.
so chart.config.data.datasets[0].data would be the original data object. when decimated we lose any additional properties or prototype a data point has. What are we thinking differently?

@kurkle
Copy link
Member

kurkle commented Jan 4, 2021

Some clarification to what I was suggesting:

currently:

chart {
  get data { return this.config.data; }
  set data(data) { this.config.data = data; }
}

proposal:

Chart {
  constructor() {
    this.data = { labels: [], datasets: [] };
  }
  set data(data) { 
    this.config.data = data;
    // update('data'), or continue requiring user to call update()
  }
  buildOrUpdateControllers() {
    const datasets = this.data.datasets;
    const configDatasets = me.config.data.datasets;
    for (let i = 0, ilen = configDatasets.length; i < ilen; i++) {
      // simplified, update logic should remain
      datasets[i] = new DatasetController(me, i, configDatasets[i]);
    }
  }
}

DatasetController {
  constructor(chart, index, config) {
    this.config = config;
    this._data = config.data || [];
    this.dataKey = '_data';
  }
  get data {
    return this[this.dataKey];
  }
  set data(value) {
    this.config.data = value;
    // update('data') or continue requiring user to call update()
  }
}

So chart.data.datasets array would contain the controllers, but setting chart.data would equal to setting chart.config.data (for compatibility, not sure if its needed).

Could also combine controller and its meta for reduced complexity and overhead, but I'm not sure if it would be good in all aspects.

@etimberg
Copy link
Member Author

I'm trying to think more about this. It could be very surprising if chart.data.datasets was the controllers and many people may be using chart.data and assuming it is the data object they passed in. In v3 we did a lot of work to stop modify the data object passed by the user and this feels like a regression backwards.

Maybe I should just update the plugin to modify the dataset and keep the changes minimal force it to be opt-in. Something like this. When decimating in future updates, the plugin would need to look for _data first since that indicates whether or not the dataset has been mutated.

dataset._data = dataset.data;
dataset._decimated = dataset.decimated;

Object.defineProperty(dataset, 'data', {
  configurable: true,
  enumerable: true,
  writable: true,
  get: function() {
    return this._decimated;
  },
  set: function(data) {
    this._data = data;
  }
});

We'd probably want something to clean this up on chart delete and put the object back to what it was.

@benmccann
Copy link
Contributor

I'm trying to think more about this. It could be very surprising if chart.data.datasets was the controllers and many people may be using chart.data and assuming it is the data object they passed in. In v3 we did a lot of work to stop modify the data object passed by the user and this feels like a regression backwards.

I agree with all of this.

Maybe I should just update the plugin to modify the dataset and keep the changes minimal force it to be opt-in.

I still think we might be able to do better than this

Here's another idea - what if we made meta.data hold the decimated data and chart.data.datasets.data could remain the original data? We'd have to be a little careful of which one we're using in the scriptable context and plugins, but hopefully it should mostly be pretty straightforward

@etimberg
Copy link
Member Author

I thought about something like that. meta.data is currently the elements, but meta.parsed is the parsed data (that would be decimated). The big downside that I thought of is that most of our examples would break subtly when decimating. We show the callbacks for the tooltips using dataset.data[index] and without decimation the index will match up, but as soon as there is any decimation, the indexes will be off and user tooltips could show the wrong data. I can see this leading to a lot of issues as users migrate over to v3.

@benmccann
Copy link
Contributor

benmccann commented Jan 16, 2021

Callbacks for tooltips are much simpler if they just use dataPoint or formattedValue (docs). Perhaps we should remove dataset from the context to avoid the possibility of users subtly tripping up as you mentioned and to encourage them to write it in the simpler way. I took a look at this and the one thing we'd need to change is that dataPoint is only the parsed value. We should probably add a rawPoint as well (#8318)

@etimberg etimberg merged commit 650956b into chartjs:master Feb 1, 2021
@etimberg etimberg deleted the decimation-take-2 branch February 1, 2021 21:37
@kurkle
Copy link
Member

kurkle commented Feb 12, 2021

@etimberg
Copy link
Member Author

I think we might need to account for that (0.5, 0.5) translation that is applied

kurkle added a commit to kurkle/Chart.js that referenced this pull request Mar 30, 2021
* Fix/scatter tooltip mode (chartjs#8354)

* scatter tooltip should be point by default
* edited mode on better level and updated docs to be bit more clear

* Rename LayoutItem.fullWidth to fullSize (chartjs#8358)

* align text inside chart for far-aligned labels passing test (chartjs#8359)

* align text inside chart for far-aligned labels

* added fix for failing test on suggestion of @kurkle

Co-authored-by: Marcel Samyn <marcel.samyn@lab900.com>

* Prevent test timeouts due to Chrome backgrounding (chartjs#8360)

* Prevent test timeouts due to Chrome backgrounding

* Add karma.conf.js to test filters

* Update type map names (chartjs#8356)

* Rename ElementOptions to ElementOptionsByType

* Rename CommonOptions to CommonElementOptions

* Rename PluginOptions to PluginOptionsByType
Add new PluginChartOptions and remove some duplicates

* Rename ScaleOptions to ScaleOptionsByType

* Use Partial where appropriate

* Shave off some bytes (chartjs#8362)

* Bump version number for beta.10 (chartjs#8364)

* Create a new hook to enable data decimation (chartjs#8255)

* Create a new hook to enable data decimation

The `beforeElementUpdate` hook can be used to decimate data. The chart
elements will not be created until after this hook has fired ensuring that
if decimation occurs, only the needed elements will be created.

* Address code review feedback

* Rename hook to beforeElementsUpdate

* Simplify parsing logic

* Add decimation plugin to the core

* Allow a dataset to specify a different data key

* Decimation plugin uses the dataKey feature

* Refactor the decimation plugin to support configurable algorithms

* Lint the plugin changes

* Tests for the dataKey feature

* Convert test files to tabs

* Standardize on tabs in ts files

* Remove the dataKey feature

* Replace dataKey usage in decimation plugin

We define a new descriptor for the `data` key allowing the
plugin to be simpler.

* Disable decimation when indexAxis is Y

* Simplify the decimation width approximation

* Resolve the indexAxis correctly in all cases

* Initial documentation

* Reverse check

* Update TS definitions for new plugin options

* Move defineProperty after bailouts

* Add destroy hook

* Prevent 2nd parse call with zero count (chartjs#8379)

* Improve radial gradient sample (chartjs#8383)

* Improve radial gradient sample
* Add hover

* Add raw data to context and rename dataPoint to parsed (chartjs#8318)

* Make the raw data point available in scriptable context
* Rename variables
* Update samples

* Update types for indexAxis (chartjs#8389)

* Add indexAxis to CoreChartOptions
* Update types for indexAxis

* Fix element creation for large dataset (chartjs#8388)

* Fix element creation for large dataset
* Fix syncing
* Remove duplication

* Fix/type dateadapter override (chartjs#8377)

* Not totally sure this is right , but since in core.adapters.js override is part of the dateadapter it seems logical it should be there. Should also fix chartjs#8369
* implemented feedback
* Declare the dataAdapter since it will be available at runtime if someone overrides it
* remove declaration. if this is giving problems in the future it might need te be added again

* Update ScriptableContext, reduce warnings (chartjs#8390)

* Update ScriptableContext, reduce warnings

* _parsed is unknown[]

* Add defaults

* static defaults.

* review update

* more cancelables

* Codeclimate: Cognitive Complexity threshold 5->6 (chartjs#8391)

* Remove options.scale, in favor of options.scales.r (chartjs#8393)

Remove options.scale, in favor of options.scales.r

* Update anchorlinks and offscreen canvas compatibility (chartjs#8395)

* Fixes wrong and missing options and to bar element and dataset doc (chartjs#8404)

* Update eslint-config-chartjs to v0.3.0 (chartjs#8406)

* Update chartjs-test-utils to v0.2.1 (chartjs#8407)

* Update chartjs-test-utils to v0.2.0

* to 0.2.1

* Small chores (chartjs#8408)

* Optimize context object construction (chartjs#8413)

* perf: context construction
* avoid setPrototypeOf

* infra: Bump CI to node 14 (chartjs#8426)

infra: Remove duplicated ES2019 plugin

* Provide a method to quickly register all imports in ESM builds (chartjs#8425)

* Add `Decimation` to all available imports list (chartjs#8430)

* Option resolution with proxies (chartjs#8374)

* Option resolution with proxies

* Remove plugin fallback to root options/defaults

* Update core plugins, reduntant font fallbacks

* Add some notes

* Update typedoc to fix dependabot alert (chartjs#8432)

* Make Chart static properties and methods read only (chartjs#8431)

* Remove unused typedoc option that is deprecated (chartjs#8433)

* Remove unused typedoc option that is deprecated

* Improved filtering for top level file changes

* perf: resolveObjectKey (chartjs#8434)

* perf: resolveObjectKey
* Fix tests
* prevent string construction

* Add a note about hover options (chartjs#8436)

* Round canvas size to 0.1px resolution (chartjs#8437)

* Round canvas size to 0.1px resolution
* Types + docs
* typofix

* perf: resolver caching (chartjs#8435)

* perf: resolver caching

* Fix plugin caching

* resetCache

* Reduce duplication, cache only by keys cached

* Reduce lines

* reduce more lines

* Double plural, noop-caching of chart level options

* Fix memory leak on destroy (chartjs#8438)

* Run compressed Size action on pull_request_target (chartjs#8440)

* Fix couple of animation bugs (chartjs#8439)

* Update .editorconfig and fix conf indents (chartjs#8442)

* Fix controller specific animations (chartjs#8444)

* Add test for default doughnut animations (chartjs#8446)

* Add markdown linting, fix errors (chartjs#8449)

* Add support for common object methods to Proxies (chartjs#8452)

* Revert "Run compressed Size action on pull_request_target (chartjs#8440)" (chartjs#8454)

This reverts commit 7e6a711.

* Add fixture for bar hide/show animation (chartjs#8453)

* Add fixture for bar hide/show animation

* Cleanup

* try using longer times

* Add tests for polarArea chart animations (chartjs#8455)

* Add tests for polarArea chart animations
* Remove commented code

* Update doughnut animation fixture (chartjs#8457)

* Update resolver fallback logic (chartjs#8456)

* add clarification about object data structure (chartjs#8447)

* add clarification about object data structure

* improved description with feedback

* fix push of wrong file

* Clarify options placement (chartjs#8427)

* improve clarity of docs by showing party qualified names in table and place of the namespace above

* add missing line

* remove partial qualified names, made some tables unusable and made it overall bit unclear. Added the namespace above each table

* fix sidebars tabs to spaces

* implement kurkles feedback

* Update polar animation tests to less error prone (chartjs#8461)

* Remove core plugin fallbacks to root options (chartjs#8462)

* Remove core plugin fallbacks to root options
* Legend font color default fallbacks

* Fix/getRelativePosition NaN value with native event (chartjs#8459)

* fix bug where onClick value returned NaN because originalEvent does not exist
* add test for this behaviour
* test to async

* Fix broken links (chartjs#8463)

* Isolate properties / modes from animation options (chartjs#8332)

* Isolate properties / modes from animation options
* tabs, something wrong with the linter
* Update misleading variable name

* Bump version to 3.0.0-beta.11 (chartjs#8441)

Co-authored-by: Evert Timberg <evert.timberg+github@gmail.com>

* Only use Path2D caching when available (chartjs#8464)

* Only use Path2D caching when available
* Try to make CC happy

* Disable fastPathSegment when data is decimated (chartjs#8465)

* Stop reading fixedStepSize from tick options (chartjs#8466)

* Decimation plugin fixes (chartjs#8467)

* fix: Decimation plugin no longer changes the data order
fix: Decimation plugin no longer duplicates data points

* Use nullOrUndef helper instead of direct check

* Compute averageX value when decimating data using minMax decimation

* Place last point of interval at real X

This reduces the fuzziness on screens with devicePixelRatio > 1

* Stop defaulting to `r` axis for Scale with id `r` (chartjs#8477)

* Update dependencies (chartjs#8474)

* Fix animation types, add test (chartjs#8476)

* LTTB Decimation (chartjs#8468)

* LTTB Decimation
* Lint fixes

* Update index.esm.d.ts (chartjs#8472)

* Update index.esm.d.ts

tickValue is to my knowledge always a number or a string so this will make it so people wont have to parse it themselfs

* Update core.scale.js

Update typedef according to types update

* Added 'hidden: boolean' to ControllerDatasetOptions type and documented the field's usage in Dataset configuration section (chartjs#8478)

* Quote globs for equal operation in windows/linux (chartjs#8481)

* Update chartjs-test-utils to v0.2.2 (chartjs#8479)

* Provide a chart-type specific definition for ParsedData (chartjs#8480)

* Provide a chart-type specific definition for ParsedData
* Fix lint error
* Code review feedback

* Fix ticks.mirror (chartjs#8482)

* Only consider visible vertical boxes in layout (chartjs#8483)

* Document the `fullSize` property of the title plugin (chartjs#8488)

* Add outerRadius option to doughnut/pie (chartjs#8487)

* Merge tooltip padding settings (chartjs#8493)

* Sample plugin in docs for canvas background (chartjs#8492)

* color done

* add example inline plugins for background image and color

* add link to css background

* improve text bit

* fix build error

* implement kurkles feedback

* fix indenting tab -> spaces

* Add linting of .mdx files + fix errors (chartjs#8496)

* Document stacked parse data (chartjs#8491)

* update borderskipped typing (chartjs#8503)

* Perf docs: tension is now 0 by default (chartjs#8500)

* Plugin options default scriptable/indexable=false (chartjs#8497)

* Plugin options default scriptable/indexable=false

* Update test

* Inherti desciptors

* Remove unreachable code

* remove unintentional change

* remove double default

* Add linting of type tests (.ts) + fix errors (chartjs#8505)

* Fix set/delete oprations on Proxies (chartjs#8506)

* data type is correct for all chart types (chartjs#8504)

* data type is correct for all chart types
* implement feedback

* Time scale: skip invalid data (chartjs#8508)

* Add resizeDelay option (chartjs#8509)

* Add resizeDelay option
* Extract helper

* Remove debug option from animation (chartjs#8512)

* Remove debug option from animation

* Add converage for visible animation

* Update visible animation fn

* Remove unreachable code paths from plugins (chartjs#8513)

* Fix layout bug when there are no visible boxes (chartjs#8507)

* Reduce duplication in PointElement (chartjs#8517)

* Config is no longer updated by options setter (chartjs#8516)

* Rename cutoutPercentage to cutout + chores (chartjs#8514)

* Fix stacking bug when a dataset is removed (chartjs#8520)

* Remove unused getRingIndex from Doughnut (chartjs#8521)

* Use null for skipped values instead of NaN (chartjs#8510)

* Use null for skipped values instead of NaN

* Document skipped values when parsing is false

* Update src/core/core.datasetController.js

Co-authored-by: Jukka Kurkela <jukka.kurkela@gmail.com>

* Update src/core/core.datasetController.js

Co-authored-by: Jukka Kurkela <jukka.kurkela@gmail.com>

* fix lint issue

* use isFinite

* revert change checking for pixel values

* ternary readability

* revert accidental paren movement

* test with parsing: false

Co-authored-by: Jukka Kurkela <jukka.kurkela@gmail.com>

* Clean up easing functions (chartjs#8518)

* Clean up easing functions
* Remove leftover comment

* Update types so instance can be assigned to a variable of type Chart (chartjs#8525)

* Update types
* Remove outdated comments

* Fix calling of onResize (chartjs#8529)

* Fix calling of onResize

* Try to fix the bugging animation test

* try again

* and the actual fix

* maybe now

* Update wording in docs about merging options (chartjs#8533)

* Types: Add couple of tests, move utils to new file (chartjs#8526)

* rename tooltip.custom property to tooltip.external (chartjs#8523)

* rename tooltip.custom property to tooltip.external

* Implement feedback

* missed 1

* Bump version to beta.12 (chartjs#8532)

* Clarify interaction docs to indicate they apply to all interactions (chartjs#8537)

* Clarify interaction docs to indicate they apply to all interactions

* Update note on modes documentation to indicate interaction options exist

* Fix ytpo

* Options need to include dataset level defaults from main chart type (chartjs#8534)

* Provide auto-registering entry point (chartjs#8429)

* Remove the constantly failing test (chartjs#8538)

* Update chart extension docs + add samples (chartjs#8540)

* Update docs on chart extensions
* Working sample for derived chart types
* Add derived axis example
* Remove duplicated line

* Resolve to false only when _fallback is used (chartjs#8542)

* Resolve to false only when _fallback is used
* Typo
* 2nd part

* Fix function support on _fallback (chartjs#8545)

* Fixes sample in the doc about missing animations configuration (chartjs#8549)

* Remove empty dependencies block from package.json (chartjs#8550)

* Fix normalize when null values at edge of dataset (chartjs#8547)

* Fix normalize when null values at edge of dataset

* Fix test with mismatched number of points

* Add test for normalized option (chartjs#8552)

* Add _allKeys descriptor for Object.keys behavior (chartjs#8553)

* update defaults in tooltip (chartjs#8554)

* Types: Update LayotPosition (chartjs#8555)

* Types: Update ScriptableContext (chartjs#8556)

* Types: Update ScriptableContext
* Add data array type test

* Remove distribution option from fixtures (chartjs#8559)

* Time: limit offset to sane values, gen >= 2 ticks (chartjs#8560)

* Use karma-spec-reporter and suppress passed (chartjs#8564)

* Tooltip specific scriptable context (chartjs#8561)

* Update plugin to use it's own tooltip context

* Scriptable tooltip option types

* Tests

* Update types to use UnionToIntersection

* Update TooltipItem to use UnionToIntersection

* Linear: Skip ticks that would overlap with min/max (chartjs#8569)

* Fix layout refit logic (chartjs#8567)

* Fix layout refit logic

* CC

* Update fixture

* Move niceNum to helpers.math, cleanup IE fallbacks (chartjs#8570)

* Rename scaleLabel to title in scale options (chartjs#8576)

* Enable multi-line axis titles (chartjs#8579)

* Relocate chart type and dataset type defaults (chartjs#8563)

* Relocate chart type and dataset type defaults

* Update types

* Separate overrides and descriptors

* Update derived sample, use merge for inherit

* Don't merge overrides

* Review update

* Bump to 3.0.0-beta.13 (chartjs#8580)

* Add `grace` option for linear scale (chartjs#8581)

* Add `grace` option for linear scale

* cc

* Add `'single'` mode for stacking (chartjs#8586)

* Add `'single'` mode for stacking

* Update fixture

* Update legend.md (chartjs#8582)

Noticed from chartjs#6185 (comment) that there is an option to get the legend in the chart, this was not documented. Only difference I noticed from kurkles screenshot is that the legend now shows in the middle instead of in the top corner.

https://jsfiddle.net/Leelenaleee/wszdv8q0/2/

* Expose radial scale point label positions (chartjs#8588)

* Move startAngle to scale options (chartjs#8593)

* scale.category: options.min/max can be index (chartjs#8594)

* Update scriptable tooltip context docs (chartjs#8599)

* Scale: refactor drawTitle, add tests (chartjs#8598)

* Scale: refactor drawTitle, add tests
* CC, lint
* update

* Fix typo in auto package (chartjs#8601)

* RadialLinear: add padding option for point labels (chartjs#8604)

* RadialLinear: add padding option for point labels

* lint

* only resolve padding once

* Fix typo in linear.mdx (chartjs#8605)

minumum -> minimum

* Disable warning of unused variables in types/tests (chartjs#8607)

* Add backgroundColor for scales (chartjs#8606)

* Add backgroundColor for scales
* Loosen the threshold

* helpers.curve cleanup (chartjs#8608)

* helpers.curve cleanup
* Use distanceBetweenPoints

* Fix typo in animations.mdx (chartjs#8615)

transtion -> transition

* Clear stacks when data is replaced (chartjs#8617)

* Add rollup-plugin-size and shave couple of bytes (chartjs#8618)

* Add rollup-plugin-size

* Shave couple of bytes

* Fix autoSkip (chartjs#8619)

* Fix autoSkip
* Add tests

* Fix some animation issues (chartjs#8616)

* Fix some animation issues

* Stop animating shared options on reset

* cc

* Update v3-migration.md (chartjs#8622)

Add note in migration guide about ability to use the `auto` register path as a npm module

* Remove rollup-plugin-size (vulnerability) (chartjs#8624)

* Types: fix bubble chart options (chartjs#8625)

* Update context documentation (chartjs#8626)

* Scale: autoSkip before fit (chartjs#8627)

Scale: autoSkip now occurs before fit in the update process

* Rename scale `gridLines` options to be clearer (chartjs#8628)

* Rename `options.gridLines` to `options.grid`

* Rename `offsetGridLines` to `offset`

* Change default autoSkipPadding to 3 (chartjs#8629)

* Radial: min 1/2 of the max radius as chartArea (chartjs#8630)

* Radial: min 1/2 of the max radius as chartArea

* Keep fooling TS

* Resize: width > 0, height = 0. Use aspectRatio 2 (chartjs#8632)

* Use font lineHeight for tooltip alignment (chartjs#8631)

* Use font lineHeight for tooltip alignment
* Remove toFontString usage from tooltip

* Radial scale point label backdrop color (chartjs#8633)

* Radial scale point label backdrop color

* Update default tests

* backdropPadding is a single setting

* Up the tolerance a bit

* Update tick backdrop padding options

* Add documentation on how plugin hooks interact with the chart (chartjs#8634)

* Add documentation on how plugin hooks interact with the chart

* Add draw.io file for flowcharts

* Document the different parts of cartesian and radial scales with examples (chartjs#8636)

* Loosen the max-statements lint rule for tests (chartjs#8638)

* Add og:image (chartjs#8635)

* Add x/y shorthand for padding options (chartjs#8637)

* Add option to turn off grouping of bar datasets (chartjs#8641)

* Add option to turn off grouping of bar datasets

* Disregard time offset

* Allow tooltip callback override in dataset (chartjs#8640)

* Linear Scale: Ability to specify a fixed number of ticks (chartjs#8643)

* Option to specify exact number of ticks on linear scale
* Fix issue description in tests
* Add tests for conditions where min/max do not align with niceMin/niceMax
* Refactor linear tick generation algorithm
* Add TS definitions
* Update docs
* Code review feedback + lint fixes

* Fix tooltip positioning issues (chartjs#8646)

* Fix tooltip positioning issues

* Update fixture, add npm run dev:ff

* Refactor determineXAlign

* Simplify more

* remove unneeded change

* Reduce duplication in drawGrid (chartjs#8647)

* Add alignToPixles option for scales (chartjs#8649)

* Exclude base-line from bar size (chartjs#8648)

* Exclude base-line from bar size

* lint

* add to types

* Use maxOverflow as minimum layout padding (chartjs#8650)

* Use maxOverflow as minimum layout padding

* fixes

* Update deps (chartjs#8654)

* Bump version to v3.0.0-beta.14 (chartjs#8653)

* Update stacked option's typing (chartjs#8656)

* Update tick positioning (chartjs#8657)

* Update tick positioning
* Update tests

* Changes defaults in documentation, applied by PR 8657 (chartjs#8660)

* Re-enable oversized boxes (chartjs#8662)

* Fix tooltip padding (chartjs#8666)

* Add textAlign for legend labels (chartjs#8665)

* Add textAlign for legend labels

* Update tests

* Fix category scale invalid data handling (chartjs#8668)

* Fix category scale invalid data handling
* Fix NaN

* Allow changing the aspect ratio (chartjs#8659)

* Allow changing the aspect ratio

* Add test and require `resize()` call

* Update to respect maintainAspectRatio

* Bumpo version to 3.0.0-rc (chartjs#8670)

* Docs/licence year update (chartjs#8671)

* Update license year

* Update docusaurus.config.js

update license year

* Update LICENSE.md

* Update external tooltip docs (chartjs#8674)

* Fix _isPointInArea for undefined point (chartjs#8678)

* Expose `formatNumber` as a helper (chartjs#8683)

* Modify Scale typing (chartjs#8681)

* Generalize toTRBL and toTRBLCorners (chartjs#8686)

* Bump to v3.0.0-rc.2 (chartjs#8687)

* Make sure all helpers are exported (chartjs#8688)

* Add typings for throttled and debounce (chartjs#8689)

* Add typings for throttled and debounce
* Review feedback
* args for fn too
* one more

* Add rollup-plugin-analyzer (chartjs#8690)

* Move autoSkip related functions to separate file (chartjs#8691)

* Move scale defaults to separate file (chartjs#8692)

* Category: parse to valid index values only (chartjs#8697)

* Allow `fill: true` and `null` in `ChartDataset.data` (chartjs#8700)

* Handle `fill: true`
* ChartDataset allow number/null data

* Update api.md (chartjs#8701)

Add clarification that you can pass type and quality options

* Line: update all points when scale range changes (chartjs#8703)

* Bump version to rc.3 (chartjs#8706)

* formatters.numeric: verify ticks length (chartjs#8705)

* formatters.numeric: verify ticks length
* use tickValue as fallback delta, add tests
* cc, chore

* fix: Scales correctly respect the locale setting when generating labels (chartjs#8710)

* Remove the comparrison doc page (chartjs#8709)

* LayoutItem.update should return void (chartjs#8714)

* Add defaults.describe/defaults.override typings (chartjs#8716)

* Minor type fixes (chartjs#8719)

* Update RadialLinearScaleOptions.pointLabels.callback type

The code passes `index` as the second parameter, and one of the tests uses this.  `@default true` doesn't seem to make sense.

* Add types for additional documented parameters in tooltip callbacks

* Distribute types as is (chartjs#8720)

I had initially seen some oddities around type augmentation for type definitions in subdirectories of `types`, and using Rollup seemed to help with that. However, now that all of Chart.js's main types are directly under `types`, there seems to be no need for this.

This simplifies the build process, since it no longer needs to use rollup-plugin-dts.

It also improves some third-party tools. For example, I'm in the habit of using WebStorm's "Go To Declaration or Usages" hotkey with third-party TypeScript definitions as a quick way of getting more information about an API. With the Rollup-generate types, that works poorly; WebStorm goes to the imported-and-re-exported symbol within the barely-readable machine-generated dist/chart.esm.d.ts file, and I have to navigate two more hops to find the actual definitions.

* Make type-tests strict (chartjs#8717)

* Bump version to 3.0.0-rc.4 (chartjs#8721)

* Point to correct type file & bump (chartjs#8724)

* Update v3-migration.md (chartjs#8725)

update sentece to make it read/sound better

* Update helper types location (chartjs#8729)

Comming from chartjs#8720 resolves chartjs#8728

* Add a convenience alias for scale options (chartjs#8732)

* Add a convenience alias for scale options

Closes chartjs#8731

* Add an automated test

* Use parameter for a more realistic test

* Document install/start/stop plugin hooks (chartjs#8733)

* Add code comment to make searching easier

* Update flowcharts

* Comment added in separate MR

* Add comments for finding registry hook calls (chartjs#8734)

* Bubble: Fix maxOverflow before elements update (chartjs#8736)

* Avoid recursive event replay loops (chartjs#8738)

* chart._lastEvent = null while processing onHover

* Pass replay flag to external tooltip

* Add test for replay

* cc

* Improved alignment of pixels in scales at low widths (chartjs#8739)

* Improved alignment of pixels in scales at low widths
* Undo scale changes

* Time: Fix offset with low data counts (chartjs#8740)

* Add note about inline plugins and registration (chartjs#8741)

* Bump version to 3.0.0-rc.6 (chartjs#8742)

* Legend: Ignore replayed events (chartjs#8749)

* Scale: draw offset grid for labels before autoSkip (chartjs#8748)

* Scale: draw offset grid for labels before autoSkip
* fix tests

* Initial work

* Update doc commands

* Updated sidebar config

* Move docs

* Update theme version and enable

* Convert to chart.js sample

* Update scripts to point to local build

* Chart.js from local build

* Simplify getting-started example

* Axis docs updated except for imported content

* Common ticks import works

* Chart type docs ported to editor plugin

* Last pages to use editor

* Fix small errors

* Frontmatter title to heading

* Remove duplicate example

* Update sidebar

* Add paths

* Remove paths

* Add getting-started back

* Update menus and add copyright to license section of the docs

* Add GA plugin

* Style sub-groups

* Remove unneeded license page since it is covered on the main page

* Remove docusaurus readme page

* Remove docusaurus files

* Fix issues in docs

* Build and deploy scripts for docs work

* Conditional base URL for nice local testing

* Use eslint-plugin-markdown

Co-authored-by: LeeLenaleee <39033624+LeeLenaleee@users.noreply.github.com>
Co-authored-by: Marcel Samyn <marcel.samyn@lab900.com>
Co-authored-by: Evert Timberg <evert.timberg+github@gmail.com>
Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com>
Co-authored-by: stockiNail <stocki.nail@gmail.com>
Co-authored-by: Kashif Shamaz <kashifshamaz21@users.noreply.github.com>
Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
Co-authored-by: 38elements <38elements@users.noreply.github.com>
Co-authored-by: coyotte508 <coyotte508@gmail.com>
Co-authored-by: Josh Kelley <joshkel@gmail.com>
Co-authored-by: Evert Timberg <evert.timberg@gmail.com>
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.

[FEATURE] Data grouping for large datasets
4 participants