Dart JS Library, how to pass callback functions

≡放荡痞女 提交于 2019-12-11 05:09:33

问题


We are trying to wrap the D3 (v4) line generator class with a Dart wrapper with https://pub.dartlang.org/packages/js. We've followed https://github.com/google/chartjs.dart/ but are having problems passing through functions.

Our wrapper looks like this:

@JS('d3')
library d3;

import 'dart:js';
import "package:js/js.dart";


@JS('line')
class Line {
  external Line();
  external String call (List<List<num>> data);
  external Line x(Function func);
  external Line y(Function func);
}

We've currently managed to get it working using:

Line line = new Line();
String path = line([[10, 20], [200, 250]]);

However we would like to set a function to access the x and y values. We've tried using:

Line line = new Line();
line.x(allowInterop((d) { return d[0]+10;}));
line([[10, 20], [200, 250]]);

This produces a stack trace:

JSFunction._apply (dart:js:1300)
#1      JSFunction.call (dart:js:1290)
#2      CardinalLine.path (package:dials/app_component.dart:42:16)
#3      _View_AppComponent2.detectChangesInternal (package:dials/app_component.template.dart:189:49)
#4      AppView.detectChanges (package:angular2/src/core/linker/view.dart:247:10)
#5      DebugAppView.detectChanges (package:angular2/src/core/linker/view.dart:367:26)
#6      AppView.detectContentChildrenChanges (package:angular2/src/core/linker/view.dart:264:31)
#7      _View_AppComponent0.detectChangesInternal (package:dials/app_component.template.dart:118:10)
#8      AppView.detectChanges (package:angular2/src/core/linker/view.dart:247:10)
#9      DebugAppView.detectChanges (package:angular2/src/core/linker/view.dart:367:26)
#10     AppView.detectViewChildrenChanges (package:angular2/src/core/linker/view.dart:270:28)
#11     AppView.detectChangesInternal (package:angular2/src/core/linker/view.dart:259:10)
#12     AppView.detectChanges (package:angular2/src/core/linker/view.dart:247:10)
#13     DebugAppView.detectChanges (package:angular2/src/core/linker/view.dart:367:26)
#14     ViewRef_.detectChanges (package:angular2/src/core/linker/view_ref.dart:123:16)
#15     ApplicationRef_.tick.<anonymous closure> (package:angular2/src/core/application_ref.dart:443:63)
#16     List.forEach (dart:core-patch/growable_array.dart:254)
#17     ApplicationRef_.tick (package:angular2/src/core/application_ref.dart:443:32)
#18     ApplicationRef_._loadComponent (package:angular2/src/core/application_ref.dart:414:10)
#19     ApplicationRef_.bootstrap.<anonymous closure> (package:angular2/src/core/application_ref.dart:401:12)
#20     ApplicationRef_.run.<anonymous closure> (package:angular2/src/core/application_ref.dart:366:26)

This appears to occur while it is trying to pass the arguments to something:

ORIGINAL EXCEPTION: V8 Exception(anonymous function) @ VM3533:1
VM3533:1 ORIGINAL STACKTRACE:(anonymous function) @ VM3533:1

Where VM3533 is:

(function() {
    var func = this;
    return function() {
        return func(Array.prototype.slice.apply(arguments));
    }
    ;
}
)

The arguments passed are:

[[MutationRecord], MutationObserver]

Where the Mutation Record consists of:

0: MutationRecord
addedNodes: NodeList[0]
attributeName: "hidden"
attributeNamespace: null
nextSibling: null
oldValue: null
previousSibling: null
removedNodes: NodeList[0]
target: div
type: "attributes"
__proto__: MutationRecord
length: 1
__proto__: Array[0]

We've tried lots of variations, including following the chartjs example, but they all end with the same stack-trace. What is the right way to do this?


回答1:


So it turns out that the function was being properly attached and called, the problem lay in the fact that I had defined the x method to be called with only one variable d.

This is how most D3 accessor functions are defined in JavaScript, you only care about the piece of data currently being modified. However D3 always passes three variables, the piece of data d, the index i, and the entire dataset data. JavaScript doesn't care that the function doesn't take the extra arguments, it just calls it with the one argument. However Dart does care, and will throw a wobbly that the function can't be applied due to an overload of arguments. This was the exception happening in VM3533.

The exception thrown is annoyingly vague, and hard to see without debugging the JavaScript.

So the correct solution is to ensure when you define a function that will be called from JavaScript that it has the exact amount of arguments that it will be called with in this context.

In this case:

Line line = new Line();
line.x(
    allowInterop(
        (List<num> d, num i, List<List<num>> data) {
            return d[0]+10;
        }
    )
);
return line([[10, 20], [30, 40]]);


来源:https://stackoverflow.com/questions/38965165/dart-js-library-how-to-pass-callback-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!