-
Notifications
You must be signed in to change notification settings - Fork 918
Description
Bug description
I have identified a bug in SfLinearGauge where dragging the marker is desynchronized (offset) when the gauge is hosted inside a custom RenderObject that applies a paint offset (drawing the child at a position different from (0,0)) without creating a new transformation layer.
This architecture is common in efficient grid layouts (like custom Slivers) where children are positioned via paint offsets rather than layout positioning.
The issue stems from _handleDragUpdate using details.localPosition. In this specific scenario, the GestureRecognizer may report a local position relative to the parent's origin if the transform isn't handled via a standard RenderTransform. Using globalToLocal(details.globalPosition) fixes this reliably.
Fix:
The issue lies in gauge/linear_gauge_render_widget.dart, specifically in the _handleDragUpdate method.
You should explicitly convert the global position to the local coordinate system using the standard RenderBox.globalToLocal method. This ensures the transformation matrix (including Paint Transforms from Slivers..) is correctly applied.
// In linear_gauge_render_widget.dart
void _handleDragUpdate(DragUpdateDetails details) {
// OLD CODE (Buggy in Custom Slivers / Paint Transforms):
// final double currentValue = _getValueFromPosition(details.localPosition);
// FIX:
// Convert global touch position to local coordinates explicitly using the RenderBox matrix.
// This ensures compatibility with parents applying paint transforms (like RenderSlivers).
final Offset localPos = globalToLocal(details.globalPosition);
final double currentValue = _getValueFromPosition(localPos);
// ... rest of the logic
}
Steps to reproduce
- Run the code.
- The Gauge appears shifted to the right (grey background).
- Try to drag the marker.
- Result: The marker jumps or is offset by ~100px relative to the cursor.
Code sample
Code sample
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
void main() {
runApp(const MaterialApp(home: App()));
}
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
double _value = 50;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Syncfusion Offset Bug')),
body: Center(
// This custom widget paints the child at (100, 0)
// simulating a slot in a grid/sliver.
child: OffsetPainterWidget(
offset: const Offset(100, 0),
child: Container(
width: 300,
height: 100,
color: Colors.grey.shade200,
child: SfLinearGauge(
minimum: 0,
maximum: 100,
markerPointers: [
LinearShapePointer(value: _value, onChanged: (v) => setState(() => _value = v)),
],
),
),
),
),
);
}
}
// A minimal RenderObject that applies a Paint Offset
// This mimics the behavior of RenderSliverDashboard or other optimized layouts.
class OffsetPainterWidget extends SingleChildRenderObjectWidget {
final Offset offset;
const OffsetPainterWidget({super.key, required Widget child, required this.offset})
: super(child: child);
@override
RenderObject createRenderObject(BuildContext context) => _RenderOffsetPainter(offset);
}
class _RenderOffsetPainter extends RenderProxyBox {
final Offset offset;
_RenderOffsetPainter(this.offset);
@override
void paint(PaintingContext context, Offset paintOffset) {
// We paint the child shifted by 'offset'
if (child != null) {
context.paintChild(child!, paintOffset + offset);
}
}
@override
void applyPaintTransform(RenderBox child, Matrix4 transform) {
// We must report this shift to the transformation matrix
transform.translateByDouble(offset.dx, offset.dy, 0, 1);
}
@override
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
// We must shift the hit-test check accordingly
if (child != null) {
return child!.hitTest(result, position: position - offset);
}
return false;
}
}Screenshots or Video
Stack Traces
Stack Traces
no stack traceOn which target platforms have you observed this bug?
Android
Flutter Doctor output
Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.38.4, on Microsoft Windows [version 10.0.26100.7171], locale fr-FR)
[√] Windows Version (11 Professionnel 64-bit, 24H2, 2009)
[√] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.14.18 (October 2025))
[√] Connected device (4 available)
[√] Network resources
