Skip to content

Scriptable options #101

@Joelius300

Description

@Joelius300

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

  • This can only be done after Robust js interop #70 and can only be released in 2.0 or later.
  • It's a breaking change because many properties will change type to ScriptableOption. However, the migration for customers should be easy since there has to be an implicit conversion operator anyway just like with IndexableOptions.
  • This feature means a lot of additional code for setting up the chart. All the IMethodHandlers have to be restored as long as we're still on json.net and all the IMethodHandlers have to be converted to functions in JavaScript. On the JavaScript-side, it would make sense to make it more dynamic. By that I mean you'd have a list of paths that are potentially IMethodHandlers and then we just loop through that list and convert them to methods if there is indeed an IMethodHandler at the given path. Because of Robust js interop #70 which makes all IMethodHandlers equal, this is possible. We could also choose this approach for the C#-side while we're still on json.net but I don't know if that makes sense. Also performance might come into play when implementing that.
  • For options that are both scriptable and indexable, we should just be able to use ScriptableOption<IndexableOption<string>>.
  • Those methods receive a scriptable option context which contains a chart field with the entire chart object. This will drain performance a lot because stringifying it on JavaScript-side is expensive and then parsing it on C# side is also expensive. I have not tested it but I can imagine that it wouldn't be usable with DelegateHandler because of the horrible performance. This might make it necessary to extend the IgnoreCallbackValue attribute to allow filtering out specific properties of a callback parameter like for example the chart field of ScriptableOptionContext.
  • Diving deeper into the callback world, we'll need to make sure that things get deserialized correctly. It'll make sense to do more unit testing around that area.
  • Just like callbacks with return value, scriptable options could only be supported on client-side blazor. The reasons have been discussed in Callbacks with return value not supported on server-side Blazor #90.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions