Draw a circle smoothly transforming to a line - flutter

I faced the problem in my Flutter app that I can't draw this kind of a shape for my Slider
What I have now is:
final paint = Paint()
..color = Colors.black
..style = PaintingStyle.fill;
final rect = Rect.fromCircle(center: center, radius: thumbRadius);
final rrect = RRect.fromRectAndRadius(
Rect.fromPoints(
Offset(rect.left - 5, rect.top),
Offset(rect.right + 5, rect.bottom),
),
Radius.circular(thumbRadius + 2),
);
canvas.drawRRect(rrect, paint);
Also, it would be great to change height of all bar, because next code changes only the size after player
SliderTheme(
data: SliderThemeData(
trackHeight: 2,
thumbShape: CustomSliderPlayer(),
),
child: Slider(...)

From the comments it looks like you are not familiar with quadratic bezier curves, they are very simple, I would recommend you to start on a Javascript canvas, they are easier to test that way and logic is the same, we move to the starting point then we draw the curve, see sample snippet below
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function dobleQuad(x, y, w, h) {
ctx.beginPath();
ctx.moveTo(x - w, y);
ctx.quadraticCurveTo(x, y - h, x + w, y);
ctx.moveTo(x - w, y);
ctx.quadraticCurveTo(x, y + h, x + w, y);
ctx.fill();
}
function drawSlider(x, y) {
ctx.moveTo(0, y - 2);
ctx.fillRect(0, y - 2, canvas.width, 4);
dobleQuad(x, y, 20, 22)
}
drawSlider(50, 50)
canvas.addEventListener('mousemove', function(evt) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
var rect = canvas.getBoundingClientRect();
drawSlider( evt.clientX - rect.left, 50 )
})
<canvas id="canvas"></canvas>
Just keep in mind that in JS it's quadraticCurveTo but in flutter quadraticBezierTo
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/quadraticCurveTo
void ctx.quadraticCurveTo(cpx, cpy, x, y);
cpx, cpy
The coordinates of the control point.
x, y
The coordinates of the end point.
https://api.flutter.dev/flutter/dart-ui/Path/quadraticBezierTo.html
void quadraticBezierTo(
double x1, double y1,
double x2, double y2
)
Adds a quadratic bezier segment that curves from the current point
to the given point (x2,y2), using the control point (x1,y1).

Related

How to draw an ellipse in GWT?

There is no context2d.ellipse in GWT, so how can I draw an ellipse? The underlying HTML5 canvas supports it, so I thought I would try and access that using a native method using the following (but it does not work)...
ellipse(context.getCanvas(),(double)x,(double)y,50.,80.,0.,0.,Math.PI*2);
...
public final native void ellipse(CanvasElement e, double x, double y, double rx, double ry, double ro, double sa, double ea)
/*-{
e.getContext("2d").ellipse(x, y, rx, ry, ro, sa, ea, false);
}-*/;
ideas / solutions?
If there is no implementation you can draw it using lines, just needs a bit of trigonometry...
function drawEllipse(x, y, rx, ry) {
ctx.beginPath();
for (i = 0; i <= 360; i++) {
a = i * Math.PI / 180
px = rx * Math.sin(a) + x
py = ry * Math.cos(a) + y
ctx.lineTo(px, py);
}
ctx.stroke();
}
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
drawEllipse(100, 100, 90, 30);
drawEllipse(100, 100, 50, 90);
drawEllipse(100, 100, 50, 25);
<canvas id=canvas width=200 height=200></canvas>

I have a line from Point A to B and I want to extend the line to Point C upto outer radius in the same angle in canvas CustomPainter Flutter

I have the coordinates of Point A(x1,y1) and Point B(x2,y2) and I want to extend the line to Point C(x3, y3) upto outer radius in the same angle in canvas CustomPainter Flutter. How to find the value of x3 and y3?. If I get the Point C I can use drawLine function to draw straight from Point A to C
Some basic trigonometry will get what you need:
let A = { x: 10, y: 10 };
let B = { x: 80, y: 20 };
let radius = 100
let angle = Math.atan2(B.y - A.y, B.x - A.x)
let C = {
x: B.x + Math.cos(angle) * radius,
y: B.y + Math.sin(angle) * radius
};
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
ctx.rect(A.x, A.y, 2, 2);
ctx.rect(B.x, B.y, 2, 2);
ctx.rect(C.x, C.y, 2, 2);
ctx.moveTo(A.x, A.y);
ctx.lineTo(C.x, C.y);
ctx.stroke();
<canvas id="c"></canvas>
What we know Points A, B and radius...
with Points A and B we can calculate the angle of the line
that is:
Math.atan2(B.y - A.y, B.x - A.x)
Then with that angle and the radius we can calculate point C:
let C = {
x: B.x + Math.cos(angle) * radius,
y: B.y + Math.sin(angle) * radius
};
Only assumption is the start of the radius, on this case I'm assuming is from point B
All that remains is to draw something with that

Snap Matrix4 rotation to 90, 180, 270, 360 degrees, Flutter

I'm currently using the matrix_gesture_detector package to scale, transform and rotate a Transform widget.
Everything works fine but to improve UX I would like to snap the widget at 90, 180, 270 or 360 degrees once the user rotates the widget close enough to said angles.
Edit: To clarify I would like the user to be able to freely rotate the widget, but snap into the nearest 90 degree rotation within whichever quadrant it is, once it gets close enough.
Hence, the solution should detect that "closeness" and then act accordingly. Please visit this link to see a GIF which shows the desired effect
How can I achieve this?
Below is the code snippet
Widget transformContainer() {
Matrix4 matrix;
GlobalKey matrixDetectorKey = GlobalKey();
return MatrixGestureDetector(
key: matrixDetectorKey,
onMatrixUpdate: (m, tm, sm, rm) {
setState(() {
matrix = MatrixGestureDetector.compose(matrix, tm, sm, rm);
});
},
child: Transform(
transform: matrix,
child: Container(
padding: EdgeInsets.all(24.0),
width: 100.0,
height: 200.0,
color: Colors.teal,
),
),
);}
For this to work, you have to check if the rotation of the matrix is closing in on a snapping point and rotate the Z-Axis to that point. I was able to write this code which works for this scenario. You may have to tune the threshold to adjust the "snappiness" to your taste.
import vector_math and use the following code:
import 'package:vector_math/vector_math_64.dart' as vec;
onMatrixUpdate: (Matrix4 m, Matrix4 tm, Matrix4 sm, Matrix4 rm) {
Matrix4 ogRm = rm.clone();
double radian = MatrixGestureDetector.decomposeToValues(m).rotation;
double degrees = vec.degrees(radian);
double delta_0 = vec.absoluteError(degrees, 0);
double delta_90 = vec.absoluteError(degrees, 90);
double delta_180 = vec.absoluteError(degrees, 180);
double delta_270 = vec.absoluteError(degrees, -90);
double threshold = 4;
if (delta_0 <= threshold) {
rm.rotateZ(vec.radians(0) - radian);
} else if (delta_90 <= threshold) {
rm.rotateZ(vec.radians(90) - radian);
} else if (delta_180 <= threshold) {
rm.rotateZ(vec.radians(180) - radian);
} else if (delta_270 <= threshold) {
rm.rotateZ(vec.radians(270) - radian);
}
// update gesture matrix
if (ogRm != rm) m = m * rm;
setState(() {
//transform your widget using this matrix
matrix = m;
});
}
Note that 360 is the same as 0, so there's no need to check for it.
MatrixGestureDetector(
onMatrixUpdate: (m, tm, sm, rm) {
setState(() {
//270 is the angle
m.rotate(m.getTranslation(), 270);
matrix4 = m;
});
},
child: Transform(
transform: matrix4,
child: Container(
padding: EdgeInsets.all(24.0),
width: 100,
height: 200,
color: Colors.teal,
),
),
),
You will have the rotate function inside the library. this code will work for snapping to 0 degrees. Basically what I am doing is if the difference in rotation and x-axis is less than 0.2 radians, I snap to 0 degrees while keeping the rotation in a separate variable. When the user moves beyond this, I add this value again and keep rotating normally.
Matrix4 _rotate(double angle, Offset focalPoint) {
double toBeRotated = 0;
var array = matrix.applyToVector3Array([0, 0, 0, 1, 0, 0]);
Offset delta = Offset(array[3] - array[0], array[4] - array[1]);
double rotation = delta.direction;
deltaAngle = deltaAngle + angle;
if ((rotation + deltaAngle).abs() > 0.2) {
toBeRotated = deltaAngle;
deltaAngle = 0;
} else if (rotation != 0 && (rotation + deltaAngle).abs() <= 0.2) {
toBeRotated = -rotation;
deltaAngle = deltaAngle + rotation;
} else {
toBeRotated = 0;
}
var c = cos(toBeRotated);
var s = sin(toBeRotated);
var dx = (1 - c) * focalPoint.dx + s * focalPoint.dy;
var dy = (1 - c) * focalPoint.dy - s * focalPoint.dx;
// ..[0] = c # x scale
// ..[1] = s # y skew
// ..[4] = -s # x skew
// ..[5] = c # y scale
// ..[10] = 1 # diagonal "one"
// ..[12] = dx # x translation
// ..[13] = dy # y translation
// ..[15] = 1 # diagonal "one"
return Matrix4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
}

raised border SWT/JFace

i can't seem to find online help on how to add different type of borders in Eclipse RCP. I know Swing has BevelBorder which can be achieved using BorderFactory. Any swt equivalence?
Try this styles: SWT.SHADOW_IN, SWT.SHADOW_OUT, SWT.SHADOW_ETCHED_IN, SWT.SHADOW_ETCHED_OUT
Please use this method for Bevel Border
private void drawBorders(GC gc, int x, int y, int w, int h) {
final Display disp = getDisplay();
final Color topleft = disp.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
final Color bottomright = disp.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
if (topleft != null && bottomright != null) {
gc.setLineWidth(1);
gc.setForeground(bottomright);
gc.drawLine(x + w, y, x + w, y + h);
gc.drawLine(x, y + h, x + w, y + h);
gc.setForeground(topleft);
gc.drawLine(x, y, x + w - 1, y);
gc.drawLine(x, y, x, y + h - 1);
}
}

middlePoint in CGContextAddArc?

i am drawing Arc through CGCOntext.I want to draw a string in the center Point of Arc.how can i fond the center point in the Arc which has been drawn through CGContext.
CGContextSetAlpha(ctx, 0.5);
CGContextSetRGBFillColor(ctx, color.red, color.green, color.blue, color.alpha );
CGContextMoveToPoint(ctx, cX, cY);
CGContextAddArc(ctx, cX, cY, radious+10, (startDeg-90)*M_PI/180.0, (endDeg-90)*M_PI/180.0, 0);
CGContextClosePath(ctx);
CGContextFillPath(ctx);
The 2nd and 3rd arguments to CGContextAddArc are the x and y coordinates for the center of the arc. Therefore, in this code, the center is at the point (cX,cY).
Edit
This code will give the coordinates for the point directly between the starting and ending points of the arc as x and y.
CGFloat x = cX + (radious+10) * (cos((startDeg-90)*M_PI/180.0) + cos((endDeg-90)*M_PI/180.0)) / 2;
CGFloat y = cY + (radious+10) * (sin((startDeg-90)*M_PI/180.0) + sin((endDeg-90)*M_PI/180.0)) / 2;