mariusmuntean / ChartJs.Blazor

Brings Chart.js charts to Blazor
https://www.iheartblazor.com/
MIT License
691 stars 152 forks source link

Scriptable options #101

Open Joelius300 opened 4 years ago

Joelius300 commented 4 years ago

Describe the feature request

While indexable options are already supported, there is currently no way to use scriptable options.

I'd like to be able to use scriptable options in the same way I can use indexable options currently and callbacks after #70.

Which charts does this feature request apply to?

All charts

Describe the solution you'd like

When the option is scriptable, I'd like to be able to assign it an IMethodHandler which will resolve the option dynamically.

Implementation draft/idea

When thinking about implementing this, I imagine a generic ScriptableOption<T> class. Along with that there would be a ScriptableOptionCallback<T> delegate which returns T and receives a ScriptableOptionContext (reference).

Then there would be an implicit conversion to T and to IMethodHandler<ScriptableOptionCallback<T>>. These two possibilities are also available as constructors. This way you can either assign a value of type T directly or a JavaScriptHandler / DelegateHandler with the delegate ScriptableOptionCallback<T>.

We'll have to make sure these get serialized correctly so when setting up the chart there would be a lot more IMethodHandler objects to restore. Also there would be a lot more callbacks to resolve on the JavaScript-side.

JavaScript equivalent

Here's an example of scriptable options taken from the chart.js scriptable line sample.

function getLineColor(ctx) {
    return utils.color(ctx.datasetIndex);
}

function alternatePointStyles(ctx) {
    var index = ctx.dataIndex;
    return index % 2 === 0 ? 'circle' : 'rect';
}

function makeHalfAsOpaque(ctx) {
    return utils.transparentize(getLineColor(ctx));
}

function adjustRadiusBasedOnData(ctx) {
    var v = ctx.dataset.data[ctx.dataIndex];
    return v < 10 ? 5
        : v < 25 ? 7
        : v < 50 ? 9
        : v < 75 ? 11
        : 15;
}

var options = {
    legend: false,
    tooltips: true,
    elements: {
        line: {
            fill: false,
            backgroundColor: getLineColor,
            borderColor: getLineColor,
        },
        point: {
            backgroundColor: getLineColor,
            hoverBackgroundColor: makeHalfAsOpaque,
            radius: adjustRadiusBasedOnData,
            pointStyle: alternatePointStyles,
            hoverRadius: 15,
        }
    }
};

Describe alternatives you've considered

There's currently not an easy alternative I know of.

Additional context