bobbingwide / sb-chart-block

Chart block for Gutenberg
GNU General Public License v3.0
6 stars 0 forks source link

Add support for charts with a proper time based axis #17

Closed bobbingwide closed 2 years ago

bobbingwide commented 2 years ago

chartJS supports charts plotted with a proper timeline.

Requirements

Proposed solution

bobbingwide commented 2 years ago

Notes from https://www.chartjs.org/docs/next/axes/cartesian/time.html

When providing data for the time scale, Chart.js uses timestamps defined as milliseconds since the epoch (midnight January 1, 1970, UTC) internally. However, Chart.js also supports all of the formats that your chosen date adapter accepts. You should use timestamps if you'd like to set parsing: false for better performance.

See also https://www.chartjs.org/docs/next/axes/cartesian/linear.html

bobbingwide commented 2 years ago

I've prototyped the JavaScript needed to support the Time Cartesian Axis with some data from my performance tests on s.b/wp55/tt2

labels contains the timestamps data contains the scores

var myChart = new Chart(ctx, {
                type: 'bar',
                data: {
                    labels: ['2021-12-13 18:34:45.371', '2021-12-13 18:35:05.330', '2021-12-13 18:41:47.633', '2021-12-13 18:45:38.566'],
                    datasets: [{
                        label: 'Scores',
                        data: [ 70, 72, 81, 76 ],
                        borderWidth: 1,
                        fill: false
                    }]
                },

For this to work the options are:

                options: {
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            type: 'time',
                            time: {
                                unit: 'minute',
                                displayFormats: {
                                    minute: 'dd MMM hh:mm '
                                }
                            },
                            title: {
                                display: true,
                                text: 'Date'
                            }
                        },

For the x axis

Prototyped at https://s.b/bw/chart/timeline.html image

Initially the JS for the time adapter was being loaded from the CDN.

<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>

I've saved that file into sb-chart-block's js folder. It'll be used when SCRIPT_DEBUG is either true or false; I don't have a non-minimised version.

bobbingwide commented 2 years ago

When I tested the result in perf I appeared to get no output for a bar chart. It worked for line chart. I tracked this down to the fact that the barThickness property was being set so small as to be invisible. This makes a lot of sense when you consider how many seconds, minutes or even hours there are in a day. If the readings are a fortnight apart the default width would be miniscule. Setting the barThickness to 3 made it visible again.

Now we have to find a common sense way of setting attributes for the following:

bobbingwide commented 2 years ago

Add some mechanism to indicate the use of type: 'time' on the x axis

Other changes as required to enable chart.js to work without too much hassle

Consider deprecation logic so that blocks don't break when new attributes are added.

bobbingwide commented 2 years ago

While testing with different values for the Time unit the block crashed with "This block has encountered an error and cannot be previewed" when the Time unit was "Day" or less and the time stamp became invalid during editing.

react_devtools_backend.js:4045 Error: 0 and 1569884400000 are too far apart with stepSize of 1 hour at Xs._generate (chart.min.js:13) at Xs.buildTicks (chart.min.js:13) at Xs.update (chart.min.js:13) at Xe (chart.min.js:13) at Object.update (chart.min.js:13) at Gn._updateLayout (chart.min.js:13) at Gn.update (chart.min.js:13) at new Gn (chart.min.js:13) at SB_chart_block.showChart (sb-chart-block.js:212) at SB_chart_block.runChart (sb-chart-block.js:247)

Requirement

bobbingwide commented 2 years ago

Test with WordPress 5.9 - without Gutenberg

In s.b/cwiccer, when I was trying to create a mileage chart with WordPress 5.9-RC2 but not Gutenberg I got the "This block has broken" message. The console log indicated that the time adapter was not loaded. It works with Gutenberg 12.3.0

Question: What am I using in Gutenberg that's not in WordPress 5.9 ?

bobbingwide commented 2 years ago

Additionally, server side rendering is incorrectly setting beginAtZero to true.; with/without Gutenberg.

bobbingwide commented 2 years ago

Here's a better stack trace for the error reported earlier https://github.com/bobbingwide/sb-chart-block/issues/17#issuecomment-1001187095

Uncaught Error: 1645660800000 and 1645747200000 are too far apart with stepSize of 1 millisecond at TimeScale._generate (chart.js?ver=499162500:13005:13) at TimeScale.buildTicks (chart.js?ver=499162500:12945:88) at TimeScale.update (chart.js?ver=499162500:5077:23) at fitBoxes (chart.js?ver=499162500:2171:9) at Object.update (chart.js?ver=499162500:2309:9) at Chart._updateLayout (chart.js?ver=499162500:6962:13) at Chart.update (chart.js?ver=499162500:6895:10) at new Chart (chart.js?ver=499162500:6667:12) at SB_chart_block.showChart (sb-chart-block.js:222:17) at SB_chart_block.runChart (sb-chart-block.js:257:27)

Try using try and catch to intercept any error(s) emanating from Chart. That worked. Now I need to find a way to explain to the user what's going wrong and how to fix it.

bobbingwide commented 2 years ago

v1.1.0 is now available from Wordpress.org. Tested with WordPress 6.0.1 with and without Gutenberg