renderCanvasLayer method

Widget renderCanvasLayer(
  1. Size availableSize
)

Implementation

Widget renderCanvasLayer(Size availableSize) {
  return RepaintBoundary(
    key: boundaryRepaintKey,
    child: Container(
      color: widget.theme.background,
      child: Listener(
        onPointerSignal: (pointerEvent) {
          if (pointerEvent is PointerScrollEvent) {
            applyZoomAtPoint(
              pointerEvent.localPosition,
              pointerEvent.scrollDelta.dy < 0 ? 1.15 : 0.87,
            );
          }
        },
        onPointerHover: (pointerEvent) =>
            detectTooltipIntersection(pointerEvent.localPosition),
        child: GestureDetector(
          onScaleStart: (gestureDetails) {
            if (isDrawingModeActive && gestureDetails.pointerCount == 1) {
              final worldCoordinates = transformScreenToWorld(
                gestureDetails.localFocalPoint.dx,
                gestureDetails.localFocalPoint.dy,
              );
              setState(() => activeStroke = [worldCoordinates]);
            } else {
              previousFocalPoint = gestureDetails.localFocalPoint;
              previousScaleGesture = 1.0;
            }
          },
          onScaleUpdate: (gestureDetails) {
            if (isDrawingModeActive &&
                gestureDetails.pointerCount == 1 &&
                activeStroke != null) {
              final worldCoordinates = transformScreenToWorld(
                gestureDetails.localFocalPoint.dx,
                gestureDetails.localFocalPoint.dy,
              );
              setState(
                () => activeStroke = [...activeStroke!, worldCoordinates],
              );
            } else {
              setState(() {
                if (gestureDetails.pointerCount >= 2 &&
                    previousScaleGesture != null) {
                  final dynamicFactor =
                      gestureDetails.scale / previousScaleGesture!;
                  currentOrigin = gestureDetails.localFocalPoint +
                      (currentOrigin - gestureDetails.localFocalPoint) *
                          dynamicFactor;
                  currentScale = (currentScale * dynamicFactor).clamp(
                    1.0,
                    3000.0,
                  );
                  previousScaleGesture = gestureDetails.scale;
                } else if (previousFocalPoint != null) {
                  currentOrigin +=
                      gestureDetails.localFocalPoint - previousFocalPoint!;
                }
                previousFocalPoint = gestureDetails.localFocalPoint;
              });
            }
          },
          onScaleEnd: (gestureDetails) {
            if (isDrawingModeActive &&
                activeStroke != null &&
                activeStroke!.length > 1) {
              final finalizedStroke = FreehandItem(
                worldPoints: List.from(activeStroke!),
                color: widget.freehandColor,
                strokeWidth: widget.freehandWidth,
              );
              setState(() {
                recordedStrokes.add(finalizedStroke);
              });
              widget.onFreehandStroke?.call(List.from(activeStroke!));
            }
            setState(() => activeStroke = null);
            previousFocalPoint = null;
            previousScaleGesture = null;
          },
          onTapUp: (gestureDetails) {
            detectTooltipIntersection(gestureDetails.localPosition);
            if (widget.onTap != null) {
              final worldCoordinates = transformScreenToWorld(
                gestureDetails.localPosition.dx,
                gestureDetails.localPosition.dy,
              );
              widget.onTap!(worldCoordinates.dx, worldCoordinates.dy);
            }
          },
          onLongPressStart: (gestureDetails) {
            if (widget.onLongPress != null) {
              final worldCoordinates = transformScreenToWorld(
                gestureDetails.localPosition.dx,
                gestureDetails.localPosition.dy,
              );
              widget.onLongPress!(worldCoordinates.dx, worldCoordinates.dy);
            }
          },
          child: Stack(
            children: [
              CustomPaint(
                size: availableSize,
                painter: CanvasRenderer(
                  origin: currentOrigin,
                  scale: currentScale,
                  items: widget.items,
                  freehandItems: recordedStrokes,
                  currentStroke: activeStroke,
                  showGrid: isGridVisible,
                  freehandColor: widget.freehandColor,
                  freehandWidth: widget.freehandWidth,
                  theme: widget.theme,
                  worldToScreen: transformWorldToScreen,
                  screenToWorld: transformScreenToWorld,
                ),
              ),
              ...widget.widgetItems.map((widgetItem) {
                final mappedScreenPoint = transformWorldToScreen(
                  widgetItem.x,
                  widgetItem.y,
                );
                return Positioned(
                  left: mappedScreenPoint.dx -
                      50 * (widgetItem.alignment.x + 1) / 2,
                  top: mappedScreenPoint.dy -
                      50 * (widgetItem.alignment.y + 1) / 2,
                  child: widgetItem.child,
                );
              }),
              if (widget.showLegend)
                LegendWidget(items: widget.items, theme: widget.theme),
              if (activeTooltip != null)
                TooltipWidget(
                  tooltipData: activeTooltip!,
                  size: availableSize,
                  theme: widget.theme,
                ),
              if (widget.showControls && widget.isFullScreen)
                FloatingToolbar(
                  theme: widget.theme,
                  drawingMode: isDrawingModeActive,
                  gridVisible: isGridVisible,
                  isFullScreen: widget.isFullScreen,
                  onFitToContent: fitToContent,
                  onResetView: resetView,
                  onZoomIn: () => zoomFromCenter(1.3),
                  onZoomOut: () => zoomFromCenter(0.77),
                  onToggleGrid: () =>
                      setState(() => isGridVisible = !isGridVisible),
                  onToggleDrawing: () => setState(
                    () => isDrawingModeActive = !isDrawingModeActive,
                  ),
                  onClearFreehand: clearFreehand,
                  onToggleFullScreen: toggleFullScreen,
                ),
              if (widget.showControls &&
                  activeTooltip != null &&
                  widget.isFullScreen)
                FloatingCoordinates(
                  tooltipData: activeTooltip!,
                  theme: widget.theme,
                ),
              if (widget.showControls && !widget.isFullScreen)
                Positioned(
                  top: 12,
                  right: 12,
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(8),
                    child: BackdropFilter(
                      filter: ui.ImageFilter.blur(sigmaX: 12.0, sigmaY: 12.0),
                      child: Container(
                        decoration: BoxDecoration(
                          color: widget.theme.background.withOpacity(0.75),
                          border: Border.all(
                            color: widget.theme.axisColor.withOpacity(0.1),
                            width: 1,
                          ),
                        ),
                        child: ControlIconButton(
                          iconData: Icons.fullscreen_rounded,
                          tooltipText: 'Pantalla Completa',
                          onTapCallback: toggleFullScreen,
                          activeTheme: widget.theme,
                        ),
                      ),
                    ),
                  ),
                ),
            ],
          ),
        ),
      ),
    ),
  );
}