Библиотека Dart JS, как передавать функции обратного вызова

Мы пытаемся обернуть класс генератора строк D3 (v4) оболочкой Dart с помощью https://pub.dartlang.org/packages/js. Мы следили за https://github.com/google/chartjs.dart/ но у нас возникают проблемы с передачей функций.

Наша обертка выглядит так:

@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);
}

В настоящее время нам удалось заставить его работать, используя:

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

Однако мы бы хотели установить функцию для доступа к значениям x и y. Мы пробовали использовать:

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

Это производит трассировку стека:

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)

Это происходит, когда он пытается передать аргументы чему-то:

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

Где VM3533 это:

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

Переданные аргументы:

[[MutationRecord], MutationObserver]

Где запись мутации состоит из:

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]

Мы перепробовали множество вариантов, в том числе следуя примеру chartjs, но все они заканчиваются одинаковой трассировкой стека. Как правильно это сделать?

1 ответ

Решение

Таким образом, оказывается, что функция была правильно присоединена и вызвана, проблема заключалась в том, что я определил метод x, который должен вызываться только с одной переменной d.

Вот как большинство функций доступа к D3 определены в JavaScript, вы заботитесь только о части данных, которые в настоящее время изменяются. Однако D3 всегда передает три переменные: часть данных d, индекс i и все данные набора данных. JavaScript не заботится о том, что функция не принимает дополнительные аргументы, она просто вызывает ее с одним аргументом. Однако Дарту все равно, и он покажет, что функция не может быть применена из-за перегрузки аргументов. Это было исключение, происходящее в VM3533.

Выданное исключение раздражающе расплывчато, и его трудно увидеть без отладки JavaScript.

Поэтому правильное решение состоит в том, чтобы при определении функции, которая будет вызываться из JavaScript, было гарантировано, что она имеет точное количество аргументов, с которыми она будет вызываться в этом контексте.

В этом случае:

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]]);
Другие вопросы по тегам