enter image description here
enter image description here
It looks like this. The center is supposed to be filled with white, but it's transparent.
How can I fill this marker?
I used this code. It's from this link.
I wanted to set the marker's color to black.
So I used this code.
`
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class MarkerGenerator {
final _markerSize;
double _circleStrokeWidth = 0;
double _circleOffset = 0;
double _outlineCircleWidth = 0;
double _fillCircleWidth = 0;
double _iconSize = 0;
double _iconOffset = 0;
MarkerGenerator(this._markerSize) {
// calculate marker dimensions
_circleStrokeWidth = _markerSize / 10.0;
_circleOffset = _markerSize / 2;
_outlineCircleWidth = _circleOffset - (_circleStrokeWidth / 2);
_fillCircleWidth = _markerSize / 3;
final outlineCircleInnerWidth = _markerSize - (2 * _circleStrokeWidth);
_iconSize = sqrt(pow(outlineCircleInnerWidth, 2) / 2);
final rectDiagonal = sqrt(2 * pow(_markerSize, 2));
final circleDistanceToCorners =
(rectDiagonal - outlineCircleInnerWidth) / 2;
_iconOffset = sqrt(pow(circleDistanceToCorners, 2) / 2);
}
/// Creates a BitmapDescriptor from an IconData
Future<BitmapDescriptor> createBitmapDescriptorFromIconData(IconData iconData,
Color iconColor, Color circleColor, Color backgroundColor) async {
final pictureRecorder = PictureRecorder();
final canvas = Canvas(pictureRecorder);
// _paintCircleFill(canvas, backgroundColor);
// _paintCircleStroke(canvas, circleColor);
_paintIcon(canvas, iconColor, iconData);
final picture = pictureRecorder.endRecording();
final image =
await picture.toImage(_markerSize.round(), _markerSize.round());
final bytes = await image.toByteData(format: ImageByteFormat.png);
return BitmapDescriptor.fromBytes(bytes!.buffer.asUint8List());
}
/// Paints the icon background
void _paintCircleFill(Canvas canvas, Color color) {
final paint = Paint()
..style = PaintingStyle.fill
..color = color;
canvas.drawCircle(
Offset(_circleOffset, _circleOffset), _fillCircleWidth, paint);
}
/// Paints a circle around the icon
void _paintCircleStroke(Canvas canvas, Color color) {
final paint = Paint()
..style = PaintingStyle.stroke
..color = color
..strokeWidth = _circleStrokeWidth;
canvas.drawCircle(
Offset(_circleOffset, _circleOffset), _outlineCircleWidth, paint);
}
/// Paints the icon
void _paintIcon(Canvas canvas, Color color, IconData iconData) {
final textPainter = TextPainter(textDirection: TextDirection.ltr);
textPainter.text = TextSpan(
text: String.fromCharCode(iconData.codePoint),
style: TextStyle(
letterSpacing: 0.0,
fontSize: _markerSize,
fontFamily: iconData.fontFamily,
color: color,
));
textPainter.layout();
// textPainter.paint(canvas, Offset(_iconOffset, _iconOffset));
textPainter.paint(canvas, Offset.zero);
}
}
`
I would like to fill in the marker.
Related
I'm Learning Custom Paint and I'm Confused About Them i referred Few Documentation but Still i'm Lacking on it.
Referrence:Curved Chart,
Paths
Some of the Code I have Mentioned Here ..Pls Help Me out of This....
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
class ChartPainter extends CustomPainter {
final List<String> x;
final List<double> y;
final double min, max;
ChartPainter(this.x, this.y, this.min, this.max);
final yLabelStyle = const TextStyle(color: Colors.white, fontSize: 14);
final xLabelStyle = const TextStyle(
color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold);
static double border = 10.0;
static double radius = 5.0;
final dotPaintFill = Paint()
..color = Colors.black
..style = PaintingStyle.fill
..strokeWidth = 2;
final linePaint = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
#override
void paint(Canvas canvas, Size size) {
final clipRect = Rect.fromLTWH(0, 0, size.width, size.height);
canvas.clipRect(clipRect);
canvas.drawPaint(Paint()..color = Colors.black);
final drawableHeight = size.height / 10.0 * border;
final drawableWidth = size.width / 15 * border;
final leftPadding = size.width / 6;
final rightPadding = size.width / 1000;
final hd = drawableHeight / 5.0;
final wd = drawableWidth / x.length.toDouble();
final height = hd * 3.0;
final width = drawableWidth;
if (height <= 0.0 || width <= 0.00) return;
if (max - min < 1.0e-6) return;
final hr = height / (max - min);
final left = border;
final top = border;
final c = Offset(left + wd / 2.0, top + height / 2.0);
_drawOutline(canvas, c, wd, height);
final points = _computePoints(c, wd, height, hr);
final fillpath = _computePath(
points, drawableHeight, width, true, leftPadding, rightPadding);
final labels = _computeLabels();
canvas.drawPath(fillpath, linePaint);
// drawvertical(canvas, c, wd, height, hr, wd);
_drawDataPoints(canvas, points, dotPaintFill, linePaint);
_drawYLabels(canvas, labels, points, wd, top);
// final c1 = Offset(c.dx, top + 4 * hd);
// _drawXLabels(canvas, c1, wd);
}
void _drawXLabels(Canvas canvas, Offset c, double wd) {
x.forEach((xp) {
drawTextCentered(canvas, c, xp, xLabelStyle, wd);
c += Offset(wd, 0);
});
}
void _drawYLabels(Canvas canvas, List<String> labels, List<Offset> points,
double wd, double top) {
var i = 0;
labels.forEach((label) {
final dp = points[i];
final dy = (dp.dy - 15.0) < top ? 15.0 : -15.0;
final ly = dp + Offset(0, dy);
drawTextCentered(canvas, ly, label, yLabelStyle, wd);
i++;
});
}
void _drawDataPoints(
Canvas canvas, List<Offset> points, Paint dotPaintFill, Paint linePaint) {
points.forEach((dp) {
canvas.drawCircle(dp, radius, dotPaintFill);
canvas.drawCircle(dp, radius, linePaint);
});
}
Path _computePath(List<Offset> points, double h, double w, bool cp,
double leftPadding, double rightPadding) {
Path path = Path();
for (var i = 0; i < points.length; i++) {
final p = points[i];
if (i == 0) {
path.moveTo(p.dx, p.dy);
path.lineTo(p.dx, p.dy);
} else {
path.lineTo(p.dx, p.dy);
}
}
return path;
}
List<Offset> _computePoints(
Offset c, double width, double height, double hr) {
List<Offset> points = [];
y.forEach((yp) {
final yy = height - (yp - min) * hr;
final dp = Offset(c.dx, c.dy - height / 2.0 + yy);
points.add(dp);
c += Offset(width, 0);
});
return points;
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
final Paint outlinePaint = Paint()
..strokeWidth = 1.0
..style = PaintingStyle.stroke
..color = Colors.white;
void _drawOutline(Canvas canvas, Offset c, double width, double height) {
y.forEach((p) {
final rect = Rect.fromCenter(center: c, width: width, height: height);
canvas.drawRect(rect, outlinePaint);
c += Offset(width, 0);
});
}
List<String> _computeLabels() {
return y.map((yp) => yp.toStringAsFixed(1)).toList();
}
TextPainter measureText(
String s, TextStyle style, double maxwidth, TextAlign align) {
final span = TextSpan(text: s, style: style);
final tp = TextPainter(
text: span, textAlign: align, textDirection: TextDirection.ltr);
tp.layout(minWidth: 0, maxWidth: maxwidth);
return tp;
}
Size drawTextCentered(
Canvas canvas, Offset c, String text, TextStyle style, double maxwidth) {
final tp = measureText(text, style, maxwidth, TextAlign.center);
final offset = c + Offset(-tp.width / 2.0, -tp.height / 2.0);
tp.paint(canvas, offset);
return tp.size;
}
}
In cubicTO() Method we assign 3 points one for control points to draw a curve . and One for Starting point and another for end point I'm confused about points and math
I try to make custom progress indicator with Custom painter but painter is not updating the value
help:
can you help me to use custom painter?
also can we change circle pointer to square box with arrow pointing to progress
class MyCsPaint extends CustomPainter {
MyCsPaint({required this.progress});
final double progress;
#override
void paint(Canvas canvas, Size size) {
Paint paintBg = Paint()
..color = Colors.teal.shade100
..strokeWidth = 1
..strokeCap = StrokeCap.round;
Paint paint = Paint()
..color = Colors.teal
..strokeWidth = 5
..strokeCap = StrokeCap.round;
Offset p1bg = Offset(size.width, size.height);
Offset p2bg = Offset(0, size.height);
Offset p2 = Offset(0, size.height);
Offset p1 = Offset(size.width * progress, size.height);
canvas.drawLine(p1bg, p2bg, paintBg);
canvas.drawLine(p1, p2, paint);
Offset pc = Offset(size.width * progress, size.height * .7);
canvas.drawCircle(pc, 10, paint);
final textStyle = ui.TextStyle(
color: Colors.black,
fontSize: 16,
);
final paragraphStyle = ui.ParagraphStyle(
textDirection: TextDirection.ltr,
);
final paragraphBuilder = ui.ParagraphBuilder(paragraphStyle)
..pushStyle(textStyle)
..addText('${progress * 100} %');
final constraints = ui.ParagraphConstraints(width: size.width);
final paragraph = paragraphBuilder.build();
paragraph.layout(constraints);
canvas.drawParagraph(paragraph, pc);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
I am using CustomPainter to display some figures, however there are some that go on top of others, the problem I have is that I want them to be displayed like this :
And the results is like this :
I don't know why, but to show them i have the code like this :
class _ZonePaint extends CustomPainter {
_ZonePaint({
[...]
});
[...]
#override
void paint(Canvas canvas, Size size) {
/// defines the look of the strokes
final _pencilPaint = Paint()
..strokeCap = StrokeCap.round
..color = secondaryMaterialColor.withOpacity(0.2)
..strokeWidth = 2.0
..style = PaintingStyle.stroke;
/// defines the look of the filling
Paint _fillPaint = Paint()
..color = secondaryMaterialColor.withOpacity(0.2)
..style = PaintingStyle.fill;
final Path path = Path();
for (int i = 0; i < list.length; i++) {
final pointList = list[i].pointList;
path.moveTo(
pointList[0].dx,
pointList[0].dy,
);
for (int f = 1; f < pointList.length; f++) {
path.lineTo(pointList[f].dx, pointList[f].dy);
}
path.close();
}
/// draw the zone
canvas.drawPath(path, _pencilPaint);
canvas.drawPath(path, _fillPaint);
}
#override
bool shouldRepaint(_ZonePaint oldDelegate) => false;
}
I am trying to create a custom marker with Round Image File
However, I am running into the [VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: type '_ByteDataView' is not a subtype of type 'Uint8List' error.
resizeImage(Uint8List file,
{int size = 150,
bool addBorder = true,
Color borderColor = Colors.orange,
double borderSize = 20,
Color titleColor = Colors.white,
Color titleBackgroundColor = Colors.black}) async {
final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint = Paint()..color;
final double radius = size / 2;
//make canvas clip path to prevent image drawing over the circle
final Path clipPath = Path();
clipPath.addRRect(RRect.fromRectAndRadius(
Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
Radius.circular(100)));
canvas.clipPath(clipPath);
//paintImage
ui.Codec codec = await ui.instantiateImageCodec(file);
ui.FrameInfo frame = await codec.getNextFrame();
paintImage(
canvas: canvas,
rect: Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
image: frame.image);
if (addBorder) {
//draw Border
paint..color = borderColor;
paint..style = PaintingStyle.stroke;
paint..strokeWidth = borderSize;
canvas.drawCircle(Offset(radius, radius), radius, paint);
}
//convert canvas as PNG bytes
final _image = await pictureRecorder
.endRecording()
.toImage(size, (size * 1.1).toInt());
final data = await _image.toByteData(format: ui.ImageByteFormat.png);
//convert PNG bytes as BitmapDescriptor
return data;
}
I'd tried with the asset images, network image and more. All have the errors. I've checked with other people's questions. However, I have no clue what are the differences and suddenly I am getting these errors?
What have I done wrong here and how can make it work?
Your function returns Future<ByteData?> so let the compiler help you by declaring that as the return type. My guess is that where you use the function you are expecting the result to be Uint8List. If you change that, the compiler should help you find it.
Here's an updated and tidied version (with clearer cascades, removal of obvious types etc)
Future<ByteData?> resizeImage(
Uint8List file, {
int size = 150,
bool addBorder = true,
Color borderColor = Colors.orange,
double borderSize = 20,
Color titleColor = Colors.white,
Color titleBackgroundColor = Colors.black,
}) async {
final pictureRecorder = ui.PictureRecorder();
final canvas = Canvas(pictureRecorder);
//make canvas clip path to prevent image drawing over the circle
canvas.clipPath(
Path()
..addRRect(RRect.fromRectAndRadius(
Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
const Radius.circular(100),
)),
);
//paintImage
final codec = await ui.instantiateImageCodec(file);
final frame = await codec.getNextFrame();
paintImage(
canvas: canvas,
rect: Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
image: frame.image,
);
if (addBorder) {
//draw Border
final radius = size / 2;
final paint = Paint()
..color = borderColor
..style = PaintingStyle.stroke
..strokeWidth = borderSize;
canvas.drawCircle(Offset(radius, radius), radius, paint);
}
//convert canvas as PNG bytes
final _image = await pictureRecorder.endRecording().toImage(
size,
(size * 1.1).toInt(),
);
return await _image.toByteData(format: ui.ImageByteFormat.png);
}
I'm new in Flutter, and I am trying to create a custom marker for google maps.
So far i have been able to create a circle with stroke, background color and icon from a canvas, but I need to add a background image from assets instead of the icon.
This is my code:
Future<BitmapDescriptor> createCustomMarkerBitmap({IconData iconData, Color iconColor, Color fillColor, Color strokeColor}) async {
ByteData data = await rootBundle.load('assets/images/iconTry.png');
Uint8List lst = new Uint8List.view(data.buffer);
Codec codec = await ui.instantiateImageCodec(lst);
FrameInfo frame = await codec.getNextFrame();
final pictureRecorder = PictureRecorder();
final canvas = Canvas(pictureRecorder);
paintCircleFill(canvas, fillColor);
paintCircleStroke(canvas, strokeColor);
paintIcon(canvas, iconColor, iconData);
paintBackgroundImage(canvas, frame.image);
final picture = pictureRecorder.endRecording();
final image = await picture.toImage(markerSize, markerSize);
final bytes = await image.toByteData(format: ImageByteFormat.png);
BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
}
void paintCircleFill(Canvas canvas, Color color) {
final paint = Paint()
..style = PaintingStyle.fill
..color = color;
canvas.drawCircle(Offset(circleOffset, circleOffset), innerRadius, paint);
}
void paintCircleStroke(Canvas canvas, Color color) {
final paint = Paint()
..style = PaintingStyle.stroke
..color = color
..strokeWidth = (stroke);
canvas.drawCircle(Offset(circleOffset, circleOffset), outerRadius, paint);
}
void paintIcon(Canvas canvas, Color color, IconData iconData) {
final textPainter = TextPainter(textDirection: TextDirection.ltr);
textPainter.text = TextSpan(
text: String.fromCharCode(iconData.codePoint),
style: TextStyle(
letterSpacing: 0.0,
fontSize: iconSize,
fontFamily: iconData.fontFamily,
color: color,
));
textPainter.layout();
textPainter.paint(canvas, Offset(iconOffset, iconOffset));
}
Use this class and call only the function createBitmapDescriptorFromIconData each time you want to create a bitmapIcon
class MarkerGenerator {
final _markerSize;
double _circleStrokeWidth;
double _circleOffset;
double _outlineCircleWidth;
double _fillCircleWidth;
double _iconSize;
double _iconOffset;
MarkerGenerator(this._markerSize) {
// calculate marker dimensions
_circleStrokeWidth = _markerSize / 12.0;
_circleOffset = _markerSize / 2;
_outlineCircleWidth = _circleOffset - (_circleStrokeWidth / 2);
_fillCircleWidth = _markerSize / 2;
final outlineCircleInnerWidth = _markerSize - (2 * _circleStrokeWidth);
_iconSize = sqrt(pow(outlineCircleInnerWidth, 2) / 4);
final rectDiagonal = sqrt(2 * pow(_markerSize, 2));
final circleDistanceToCorners = (rectDiagonal - outlineCircleInnerWidth) / 2;
_iconOffset = sqrt(pow(circleDistanceToCorners, 2) / 1);
}
/// Creates a BitmapDescriptor from an IconData
Future<BitmapDescriptor> createBitmapDescriptorFromIconData(IconData iconData, Color iconColor, Color circleColor, Color backgroundColor) async {
final pictureRecorder = PictureRecorder();
final canvas = Canvas(pictureRecorder);
_paintCircleFill(canvas, backgroundColor);
_paintCircleStroke(canvas, circleColor);
_paintIcon(canvas, iconColor, iconData);
final picture = pictureRecorder.endRecording();
final image = await picture.toImage(_markerSize.round(), _markerSize.round());
final bytes = await image.toByteData(format: ImageByteFormat.png);
return BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
}
/// Paints the icon background
void _paintCircleFill(Canvas canvas, Color color) {
final paint = Paint()
..style = PaintingStyle.fill
..color = color;
canvas.drawCircle(Offset(_circleOffset, _circleOffset), _fillCircleWidth, paint);
}
/// Paints a circle around the icon
void _paintCircleStroke(Canvas canvas, Color color) {
final paint = Paint()
..style = PaintingStyle.stroke
..color = color
..strokeWidth = _circleStrokeWidth;
canvas.drawCircle(Offset(_circleOffset, _circleOffset), _outlineCircleWidth, paint);
}
/// Paints the icon
void _paintIcon(Canvas canvas, Color color, IconData iconData) {
final textPainter = TextPainter(textDirection: TextDirection.ltr);
textPainter.text = TextSpan(
text: String.fromCharCode(iconData.codePoint),
style: TextStyle(
letterSpacing: 0.0,
fontSize: _iconSize,
fontFamily: iconData.fontFamily,
package: iconData.fontPackage,
color: color,
));
textPainter.layout();
textPainter.paint(canvas, Offset(_iconOffset, _iconOffset));
}
}
Edit
If you want to use an asset instead, this class may be helpful
class Common {
static Future<Uint8List> getBytesFromAsset(String path, int width) async {
ByteData data = await rootBundle.load(path);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
ui.FrameInfo fi = await codec.getNextFrame();
return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
}
}
Then to create a bitmapIcon, you'll do like this
var bytes = await Common.getBytesFromAsset("your/asset/path", 100);
BitmapDescriptor.fromBytes(bytes);