Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added onTap feature for chartJS #1690

Merged
merged 4 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 37 additions & 11 deletions modules/ensemble/lib/widget/visualization/chart_js.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import 'dart:io';
import 'dart:convert';
import 'dart:math';

import 'package:ensemble/framework/action.dart';
import 'package:ensemble/framework/event.dart';
import 'package:ensemble/screen_controller.dart';
import 'package:ensemble_ts_interpreter/parser/newjs_interpreter.dart';
import 'package:flutter/material.dart';
import 'package:js_widget/js_widget.dart';
import 'package:ensemble/framework/widget/widget.dart';
import 'package:ensemble/util/utils.dart';
import 'package:ensemble/widget/helpers/controllers.dart';
import 'package:ensemble_ts_interpreter/invokables/invokable.dart';
import 'package:ensemble_ts_interpreter/parser/newjs_interpreter.dart';
import 'package:flutter/material.dart';
import 'package:js_widget/js_widget.dart';
import 'dart:convert';

class ChartJsController extends WidgetController {
ChartJsController() {
Expand All @@ -21,6 +22,7 @@ class ChartJsController extends WidgetController {
String get chartId => id!;
dynamic config = '';
Function? evalScript;
EnsembleAction? onTap;
}

class ChartJs extends StatefulWidget
Expand Down Expand Up @@ -125,7 +127,9 @@ class ChartJs extends StatefulWidget
} else {
_controller.config = value;
}
}
},
'onTap': (funcDefinition) => _controller.onTap =
EnsembleAction.from(funcDefinition, initiator: this),
};
}
}
Expand Down Expand Up @@ -161,15 +165,37 @@ class ChartJsState extends EWidgetState<ChartJs> {
id: widget.controller.id!,
createHtmlTag: () =>
'<div id="${widget.controller.chartDiv}"><canvas id="${widget.controller.chartId}"></canvas></div>',
scriptToInstantiate: (String c) {
return 'if (typeof ${widget.controller.chartVar} !== "undefined") ${widget.controller.chartVar}.destroy();${widget.controller.chartVar} = new Chart(document.getElementById("${widget.controller.chartId}"), $c);${widget.controller.chartVar}.update();';
scriptToInstantiate: (String config) {
return '''
if (typeof ${widget.controller.chartVar} !== "undefined") {
${widget.controller.chartVar}.destroy();
}
${widget.controller.chartVar} = new Chart(document.getElementById("${widget.controller.chartId}"), $config);

// Add click event listener to the chart
document.getElementById("${widget.controller.chartId}").onclick = function(event) {
// Notify Flutter about the click event (no need to send data)
if (window.dispatchEvent) {
var eventDetail = new CustomEvent('callFlutter', { detail: 'onTap' });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we are sending the event anyway, why not send data as well? It is important in general to send the data along with the event even if not needed for this use case

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I have updated the available data in it.

window.dispatchEvent(eventDetail);
} else {
console.log("Flutter handler not available");
}
};
${widget.controller.chartVar}.update();
''';
},
size: Size(widget.controller.width.toDouble(),
widget.controller.height.toDouble()),
size: Size(widget.controller.width.toDouble(), widget.controller.height.toDouble()),
data: widget.controller.config,
scripts: const [
"https://cdn.jsdelivr.net/npm/chart.js",
],
listener: (msg) {
if (msg == 'onTap' && widget.controller.onTap != null) {
ScreenController().executeAction(context, widget.controller.onTap!,
event: EnsembleEvent(widget));
}
},
);
return jsWidget!;
}
Expand Down
16 changes: 15 additions & 1 deletion modules/js_widget/lib/src/mobile/js_widget.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher_string.dart';
// Import for Android features.
Expand Down Expand Up @@ -138,7 +140,19 @@ class JsWidgetState extends State<JsWidget> {
fit: StackFit.expand,
children: [
!_isLoaded ? widget.loader : const SizedBox.shrink(),
WebViewWidget(controller: controller),
WebViewWidget(
controller: controller,
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

configure the gestureRecognizers only if a listener has been specified. You don't want to capture clicks if there is no listener

Factory<OneSequenceGestureRecognizer>(
() => TapGestureRecognizer()
..onTapDown = (TapDownDetails details) {
if (widget.listener != null) {
widget.listener!('onTap'); // Notify on tap
}
},
),
},
),
],
),
);
Expand Down
10 changes: 9 additions & 1 deletion modules/js_widget/lib/src/web/js_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class JsWidgetState extends State<JsWidget> {
void initState() {
if (widget.listener != null) {
addListener(widget.id, widget.listener!);
init(globalListener);
_setupFlutterWebCommunication();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the init method sets up the interop. How will it work without calling that method?

}
if (widget.preCreateScript != null) {
eval(widget.preCreateScript!());
Expand All @@ -114,6 +114,14 @@ class JsWidgetState extends State<JsWidget> {
});
super.initState();
}
// Setup Flutter web communication for JS interactions
void _setupFlutterWebCommunication() {
html.window.addEventListener('callFlutter', (event) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

who dispatches the callFlutter event? why not use the interop?

final customEvent = event as html.CustomEvent;
final msg = customEvent.detail;
globalListener(widget.id, msg);
});
}

@override
void dispose() {
Expand Down
Loading