feat!: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML)

This commit is contained in:
Nick Fisher
2024-08-21 17:17:58 +08:00
parent d868fd6970
commit d7664a9746
7 changed files with 95 additions and 18 deletions

View File

@@ -85,7 +85,6 @@ abstract class ThermionViewer {
/// ///
Future render(); Future render();
/// ///
/// Render a single frame to the viewport and copy the pixel buffer to [out]. /// Render a single frame to the viewport and copy the pixel buffer to [out].
/// ///

View File

@@ -9,10 +9,8 @@ import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dar
/// surface in a Flutter application and lifecycle listeners to pause rendering /// surface in a Flutter application and lifecycle listeners to pause rendering
/// when the app is inactive or in the background. /// when the app is inactive or in the background.
/// Call [createViewer] to create an instance of [ThermionViewer]. /// Call [createViewer] to create an instance of [ThermionViewer].
/// This is a lightweight singleton that
/// ///
class ThermionFlutterPlugin { class ThermionFlutterPlugin {
ThermionFlutterPlugin._(); ThermionFlutterPlugin._();
static AppLifecycleListener? _appLifecycleListener; static AppLifecycleListener? _appLifecycleListener;
@@ -92,8 +90,12 @@ class ThermionFlutterPlugin {
} }
@override @override
static Future<ThermionFlutterTexture?> resizeTexture(ThermionFlutterTexture texture, static Future<ThermionFlutterTexture?> resizeTexture(
int width, int height, int offsetLeft, int offsetRight) async { ThermionFlutterTexture texture,
int width,
int height,
int offsetLeft,
int offsetRight) async {
return ThermionFlutterPlatform.instance return ThermionFlutterPlatform.instance
.resizeTexture(texture, width, height, offsetLeft, offsetRight); .resizeTexture(texture, width, height, offsetLeft, offsetRight);
} }

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion/widgets/thermion_widget_web.dart';
import 'dart:async'; import 'dart:async';
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
@@ -82,17 +83,27 @@ class _ThermionWidgetState extends State<ThermionWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (kIsWeb) {
if (_texture == null || _resizing) {
return widget.initial ?? Container(color: Colors.red);
}
return ResizeObserver(
onResized: _resizeTexture, child: ThermionWidgetWeb());
}
if (_texture?.usesBackingWindow == true) { if (_texture?.usesBackingWindow == true) {
return ResizeObserver( return ResizeObserver(
onResized: _resizeTexture, onResized: _resizeTexture,
child: Stack(children: [ child: Stack(children: [
Positioned.fill(child: CustomPaint(painter: TransparencyPainter())) Positioned.fill(child: CustomPaint(painter: TransparencyPainter()))
])); ]));
} }
if (_texture == null || _resizing) { if (_texture == null || _resizing) {
return widget.initial ?? return widget.initial ??
Container(color: kIsWeb ? Colors.transparent : Colors.red); Container(
color:
kIsWeb ? const Color.fromARGB(0, 170, 129, 129) : Colors.red);
} }
var textureWidget = Texture( var textureWidget = Texture(
@@ -131,3 +142,4 @@ class TransparencyPainter extends CustomPainter {
@override @override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false; bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
} }

View File

@@ -0,0 +1,3 @@
export 'thermion_widget_web_stub.dart'
if (dart.library.js_interop) 'thermion_widget_web_impl.dart';

View File

@@ -0,0 +1,49 @@
import 'dart:js_util';
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
import 'dart:ui' as ui;
import 'dart:ui_web' as ui_web;
import 'package:flutter/material.dart';
import 'package:web/web.dart';
import 'package:flutter/widgets.dart';
import 'dart:html' as html;
class ThermionWidgetWeb extends StatefulWidget {
@override
State<StatefulWidget> createState() => ThermionWidgetWebState();
}
class ThermionWidgetWebState extends State<ThermionWidgetWeb> {
ui.Image? _img;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
capture();
});
}
Future capture() async {
try {
final ImageBitmap newSource = await promiseToFuture<ImageBitmap>(
window.createImageBitmap(
document.getElementById("canvas") as HTMLCanvasElement));
_img = await ui_web.createImageFromImageBitmap(newSource);
setState(() {});
WidgetsBinding.instance.addPostFrameCallback((_) {
capture();
});
} catch (err) {
print(err);
}
}
@override
Widget build(BuildContext context) {
if (_img == null) {
return Container(color: Colors.transparent);
}
return RawImage(image: _img!);
}
}

View File

@@ -0,0 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class ThermionWidgetWeb extends StatefulWidget {
@override
State<StatefulWidget> createState() => throw Exception();
}

View File

@@ -17,6 +17,14 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform {
@override @override
Future<ThermionFlutterTexture?> createTexture( Future<ThermionFlutterTexture?> createTexture(
int width, int height, int offsetLeft, int offsetRight) async { int width, int height, int offsetLeft, int offsetRight) async {
await _viewer!.destroySwapChain();
await _viewer!.createSwapChain(width, height);
_viewer!.updateViewportAndCameraProjection(width, height, 1.0);
final canvas = document.getElementById("canvas") as HTMLCanvasElement;
canvas.width = width;
canvas.height = height;
return ThermionFlutterTexture(null, null, 0, 0, null); return ThermionFlutterTexture(null, null, 0, 0, null);
} }
@@ -39,15 +47,12 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform {
} }
Future<ThermionViewer> createViewer({String? uberArchivePath}) async { Future<ThermionViewer> createViewer({String? uberArchivePath}) async {
final canvas = document.getElementById("canvas") as HTMLCanvasElement;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var width = window.innerWidth;
var height = window.innerHeight;
_viewer = ThermionViewerWasm(assetPathPrefix: "/assets/"); _viewer = ThermionViewerWasm(assetPathPrefix: "/assets/");
await _viewer!.initialize(width, height, uberArchivePath: uberArchivePath); final canvas = document.createElement("canvas") as HTMLCanvasElement;
canvas.id = "canvas";
document.body!.appendChild(canvas);
canvas.style.display = 'none';
await _viewer!.initialize(0, 0, uberArchivePath:uberArchivePath);
return _viewer!; return _viewer!;
} }
} }