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 0a720fae72
commit 10cab8dcb4
7 changed files with 95 additions and 18 deletions

View File

@@ -85,7 +85,6 @@ abstract class ThermionViewer {
///
Future render();
///
/// 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
/// when the app is inactive or in the background.
/// Call [createViewer] to create an instance of [ThermionViewer].
/// This is a lightweight singleton that
///
class ThermionFlutterPlugin {
ThermionFlutterPlugin._();
static AppLifecycleListener? _appLifecycleListener;
@@ -92,8 +90,12 @@ class ThermionFlutterPlugin {
}
@override
static Future<ThermionFlutterTexture?> resizeTexture(ThermionFlutterTexture texture,
int width, int height, int offsetLeft, int offsetRight) async {
static Future<ThermionFlutterTexture?> resizeTexture(
ThermionFlutterTexture texture,
int width,
int height,
int offsetLeft,
int offsetRight) async {
return ThermionFlutterPlatform.instance
.resizeTexture(texture, width, height, offsetLeft, offsetRight);
}

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion/widgets/thermion_widget_web.dart';
import 'dart:async';
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
@@ -82,17 +83,27 @@ class _ThermionWidgetState extends State<ThermionWidget> {
@override
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) {
return ResizeObserver(
onResized: _resizeTexture,
child: Stack(children: [
Positioned.fill(child: CustomPaint(painter: TransparencyPainter()))
]));
onResized: _resizeTexture,
child: Stack(children: [
Positioned.fill(child: CustomPaint(painter: TransparencyPainter()))
]));
}
if (_texture == null || _resizing) {
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(
@@ -131,3 +142,4 @@ class TransparencyPainter extends CustomPainter {
@override
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
Future<ThermionFlutterTexture?> createTexture(
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);
}
@@ -39,15 +47,12 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform {
}
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/");
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!;
}
}