grid.dart 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import 'dart:math';
  2. import 'package:flutter/material.dart';
  3. import 'package:grpc/grpc_web.dart';
  4. import 'package:cyclop/cyclop.dart';
  5. import 'src/color_ref.dart';
  6. import 'src/connection/ws.dart';
  7. import 'src/widget/square.dart';
  8. class TransformationsDemo extends StatefulWidget {
  9. const TransformationsDemo({Key? key}) : super(key: key);
  10. @override
  11. State<TransformationsDemo> createState() => _TransformationsDemoState();
  12. }
  13. class _TransformationsDemoState extends State<TransformationsDemo>
  14. with TickerProviderStateMixin {
  15. final GlobalKey _targetKey = GlobalKey();
  16. Map<Point<int>, Widget> elements = <Point<int>, Widget>{};
  17. Color appbarColor = Colors.blueGrey;
  18. Set<Color> swatches = Colors.primaries.map((e) => Color(e.value)).toSet();
  19. double minScale = 2;
  20. ColorRef cc = ColorRef();
  21. final TransformationController _transformationController =
  22. TransformationController();
  23. Animation<Matrix4>? _animationReset;
  24. late AnimationController _controllerReset;
  25. Matrix4? _homeMatrix;
  26. final channel = GrpcWebClientChannel.xhr(Uri.parse('http://localhost:8080'));
  27. @override
  28. void initState() {
  29. super.initState();
  30. WebRTCChannels().connect((x) {});
  31. // _controllerReset = AnimationController(
  32. // vsync: this,
  33. // );
  34. }
  35. @override
  36. Widget build(BuildContext context) {
  37. // The scene is drawn by a CustomPaint, but user interaction is handled by
  38. // the InteractiveViewer parent widget.
  39. return Scaffold(
  40. backgroundColor: Theme.of(context).colorScheme.primary,
  41. // appBar: AppBar(
  42. // automaticallyImplyLeading: false,
  43. // title: const Text('title'),
  44. // ),
  45. body: Container(
  46. color: Colors.white,
  47. child: LayoutBuilder(
  48. builder: (context, constraints) {
  49. // Start the first render, start the scene centered in the viewport.
  50. if (_homeMatrix == null) {
  51. _homeMatrix = Matrix4.identity() * minScale
  52. ..translate(0, 0);
  53. _transformationController.value = _homeMatrix!;
  54. elements = _start(
  55. context: context,
  56. channel: channel,
  57. transformationController: _transformationController);
  58. // _onUpdate(context: context);
  59. }
  60. return ClipRect(
  61. child: MouseRegion(
  62. cursor: SystemMouseCursors.click,
  63. child: GestureDetector(
  64. behavior: HitTestBehavior.opaque,
  65. // onTapUp: _onTapUp,
  66. child: InteractiveViewer(
  67. constrained: false,
  68. key: _targetKey,
  69. transformationController: _transformationController,
  70. boundaryMargin: EdgeInsets.all(0),
  71. minScale: minScale,
  72. maxScale: 30,
  73. // onInteractionStart: _onScaleStart,
  74. onInteractionUpdate: _onInteractionUpdate,
  75. onInteractionEnd: _onInteractionEnd,
  76. child: SizedBox(
  77. width: 256 * 90,
  78. height: 256 * 53,
  79. child: Stack(children: elements.values.toList()),
  80. ),
  81. ),
  82. ),
  83. ),
  84. );
  85. },
  86. ),
  87. ),
  88. // persistentFooterButtons: [],
  89. floatingActionButton: ColorButton(
  90. darkMode: true,
  91. key: const Key('c2'),
  92. color: appbarColor,
  93. boxShape: BoxShape.circle,
  94. swatches: swatches,
  95. size: 64,
  96. config: const ColorPickerConfig(
  97. enableOpacity: false,
  98. enableLibrary: true,
  99. ),
  100. onColorChanged: (value) => setState(() {
  101. appbarColor = value;
  102. cc.setColor(appbarColor);
  103. }),
  104. onSwatchesChanged: (newSwatches) =>
  105. setState(() => swatches = newSwatches),
  106. ),
  107. );
  108. }
  109. @override
  110. void dispose() {
  111. // _controllerReset.dispose();
  112. super.dispose();
  113. }
  114. void _onInteractionUpdate(ScaleUpdateDetails details) {
  115. _onUpdate();
  116. }
  117. void _onUpdate({BuildContext? context}) {
  118. var context2 = context ?? _targetKey.currentContext!;
  119. setState(() {
  120. _start(
  121. context: context2,
  122. channel: channel,
  123. transformationController: _transformationController,
  124. elements: elements);
  125. });
  126. }
  127. Map<Point<int>, Widget> _start(
  128. {required BuildContext context,
  129. required GrpcWebClientChannel channel,
  130. required TransformationController transformationController,
  131. Map<Point<int>, Widget>? elements}) {
  132. var bounds = MediaQuery.of(context).size;
  133. var topLeft = transformationController.toScene(bounds.topLeft(Offset.zero));
  134. var bottomRight =
  135. transformationController.toScene(bounds.bottomRight(Offset.zero));
  136. var newSet = <Point<int>>{};
  137. var rec = Rectangle<int>.fromPoints(
  138. _offsetToIndex(topLeft), _offsetToIndex(bottomRight));
  139. for (var i = rec.left; i <= rec.right; i++) {
  140. for (var j = rec.top; j <= rec.bottom; j++) {
  141. newSet.add(Point<int>(i, j));
  142. }
  143. }
  144. var elements2 = elements ?? <Point<int>, Widget>{};
  145. newSet
  146. .difference(Set.from(elements2.keys))
  147. .forEach((point) => elements2[point] ??= Container(
  148. margin:
  149. EdgeInsets.only(left: 256.0 * point.x, top: 256.0 * point.y),
  150. child: SquareComponent(point, cc),
  151. ));
  152. Set.from(elements2.keys).difference(newSet).forEach(
  153. (point) => elements2.remove(point),
  154. );
  155. // print(elements2.length);
  156. // WebRTCChannels().connect();
  157. return elements2;
  158. }
  159. void _onInteractionEnd(ScaleEndDetails details) => _onUpdate();
  160. }
  161. Point<int> _offsetToIndex(Offset offset) {
  162. offset = offset / 256.0;
  163. var x = offset.dx.floor();
  164. var y = offset.dy.floor();
  165. if (x < 0) x = 0;
  166. if (y < 0) y = 0;
  167. return Point<int>(x, y);
  168. }