Draw dashed arc with flutter - dart

Is there some way to draw a dashed arc in Flutter?
At the moment I'm using canvas.drawArc but I don't know how to get the correct result.
canvas.drawArc(
rectangle,
startAngle,
fullArcRadius,
false,
Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 2.0,
);
dashed-arc

Unfortunately, flutter doesn't handle dashes all that well. There is a plugin that helps with it though: path_drawing
Using that, you can draw any path dashed simply by wrapping it in the dashPath function. That sounds simple enough, but it means that you can't use the canvas.drawArc method which complicates things a little. You have to use canvas.drawPath instead and figure out how to draw a path which is the same as that arc.
This is how I'd do it (and I've put in the code I use to draw the item fit to the canvas which you can use or ignore as you see fit):
import 'package:flutter/material.dart';
import 'package:path_drawing/path_drawing.dart';
class DashedArc extends CustomPainter {
final Color color;
DashedArc({Color color}) : color = color ?? Colors.white;
#override
void paint(Canvas canvas, Size size) {
// TODO: remove me. This makes it easier to tell
// where the canvas should be
canvas.drawRect(
Offset.zero & size,
Paint()
..color = Colors.black
..style = PaintingStyle.stroke);
var width = 520, height = 520, scale;
// this is a simple Boxfit calculation for the `cover` mode. You could
// use the applyBoxFit function instead, but as it doesn't return a
// centered rect it's almost as much work to use it as to just do it
// manually (unless someone has a better way in which case I'm all ears!)
double rw = size.width / width;
double rh = size.height / height;
double actualWidth, actualHeight, offsetLeft, offsetTop;
if (rw > rh) {
// height is constraining attribute so scale to it
actualWidth = rh * width;
actualHeight = size.height;
offsetTop = 0.0;
offsetLeft = (size.width - actualWidth) / 2.0;
scale = rh;
} else {
// width is constraining attribute so scale to it
actualHeight = rw * height;
actualWidth = size.width;
offsetLeft = 0.0;
offsetTop = (size.height - actualHeight) / 2.0;
scale = rw;
}
canvas.translate(offsetLeft, offsetTop);
canvas.scale(scale);
// parameters from the original drawing (guesstimated a bit using
// preview...)
const double startX = 60;
const double startY = 430; // flutter starts counting from top left
const double dashSize = 5;
const double gapSize = 16;
canvas.drawPath(
dashPath(
Path()
// tell the path where to start
..moveTo(startX, startY)
// the offset tells the arc where to end, the radius is the
// radius of the circle, and largeArc tells it to use the
// big part of the circle rather than the small one.
// The implied parameter `clockwise` means that it starts the arc
// and draw clockwise; setting this to false would result in a large
// arc below!
..arcToPoint(Offset(520 - startX, startY), radius: Radius.circular(260), largeArc: true),
// dash is `dashSize` long followed by a gap `gapSize` long
dashArray: CircularIntervalList<double>([dashSize, gapSize]),
dashOffset: DashOffset.percentage(0.005)),
Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = dashSize);
}
#override
bool shouldRepaint(DashedArc oldDelegate) {
return oldDelegate.color != this.color;
}
}

Related

How to draw different Pattern in flutter?

I want to draw the different pattern in the flutter like this
Although this code is javascript is given in this link
I used ImageShader and used shader property of Paint Function
device transform is used to get the device pixel so that it can render the effect
This is my paint method look like...
final double devicePixelRatio = ui.window.devicePixelRatio;
#override
void paint(Canvas canvas, Size size) {
final Float64List deviceTransform = new Float64List(16)
..[0] = devicePixelRatio
..[5] = devicePixelRatio
..[10] = 1.0
..[15] = 2.0;
Float64List matrix = new Float64List(16);
print('matrix is $matrix');
print('image is coming in paint $image');
Paint paint = new Paint()
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..shader = ImageShader(
image, TileMode.repeated, TileMode.repeated, deviceTransform)
..strokeWidth = 40.2;
paths.forEach((path) {
canvas.drawPath(path, paint);
});
repaint = false;
}

Animate multiple shapes in UIView

I have a custom class that inherit from UIView. In the draw method I draw several shapes including some circles. I want to animate the color (now stroke color) of the circles independent of each other, e.g. I would like the color of one or more the circles to "pulse" or flash (using ease-in/ease-out and not linearly).
What would be the best way to archive this?
It would be great to be able to use the built-in animation code (CABasicAnimation and the like) but I'm not sure how?
EDIT: Here's the code involved. (I am using Xamarin.iOS but my question is not specific to this).
CGColor[] circleColors;
public override void Draw (RectangleF rect)
{
base.Draw (rect);
using (CGContext g = UIGraphics.GetCurrentContext ()) {
g.SetLineWidth(4);
float size = rect.Width > rect.Height ? rect.Height : rect.Width;
float xCenter = ((rect.Width - size) / 2) + (size/2);
float yCenter = ((rect.Height - size) / 2) + (size/2);
float d = size / (rws.NumCircles*2+2);
var circleRect = new RectangleF (xCenter, yCenter, 0, 0);
for (int i = 0; i < rws.NumCircles; i++) {
circleRect.X -= d;
circleRect.Y -= d;
circleRect.Width += d*2;
circleRect.Height += d*2;
CGPath path = new CGPath ();
path.AddEllipseInRect (circleRect);
g.SetStrokeColor (circleColors [i]);
g.AddPath (path);
g.StrokePath ();
}
}
}
You need to move all your drawing code to a subclass of CALayer, and decide parameters which, once varied, will produce the desired animations. Convert these parameters to the layer's properties, and you can animate the layer's properties with CABasicAnimation (or even [UIView animateXXX]).
See this SO question for more information.
Make sure that you set the layer's rasterizationScale to [UIScreen mainScreen].scale to avoid blurs on Retina.

how to add some text to a static image programatically, Using MonoTouch?

I have a static image of size 1024*768 with some logo on one side,
i want to have some text added to that image eg: Page 1, (on another side)
i got some code from
public override void ViewDidLoad ()
{
try {
base.ViewDidLoad ();
UIImage ii = new UIImage (Path.Combine (NSBundle.MainBundle.BundleUrl.ToString ().Replace ("%20", " ").Replace ("file://", ""), "images2.png"));
RectangleF wholeImageRect = new RectangleF (0, 0, ii.CGImage.Width, ii.CGImage.Height);
imageView = new UIImageView (wholeImageRect);
this.View.AddSubview (imageView);
imageView.Image = DrawVerticalText ("Trail Text", 100, 100);
Console.Write ("Switch to Simulator now to see ");
Console.WriteLine ("some stupid graphics tricks");
} catch (Exception ex) {
}
}
public static UIImage DrawVerticalText (string text, int width, int height)
{
try {
float centerX = width / 2;
float centerY = height / 2;
//Create the graphics context
byte[] mybyteArray;
CGImage tt = null;
UIImage ii = new UIImage (Path.Combine (NSBundle.MainBundle.BundleUrl.ToString ().Replace ("%20", " ").Replace ("file://", ""), "images2.png"));
using (NSData imagedata = ii.AsPNG ()) {
mybyteArray = new byte[imagedata.Length];
System.Runtime.InteropServices.Marshal.Copy (imagedata.Bytes, mybyteArray, 0, Convert.ToInt32 (imagedata.Length));
using (CGBitmapContext ctx = new CGBitmapContext (mybyteArray, width, height, 8, 4 * width, CGColorSpace.CreateDeviceRGB (), CGImageAlphaInfo.PremultipliedFirst)) {
//Set the font
ctx.SelectFont ("Arial", 16f, CGTextEncoding.MacRoman);
//Measure the text's width - This involves drawing an invisible string to calculate the X position difference
float start, end, textWidth;
//Get the texts current position
start = ctx.TextPosition.X;
//Set the drawing mode to invisible
ctx.SetTextDrawingMode (CGTextDrawingMode.Invisible);
//Draw the text at the current position
ctx.ShowText (text);
//Get the end position
end = ctx.TextPosition.X;
//Subtract start from end to get the text's width
textWidth = end - start;
//Set the fill color to blue
ctx.SetRGBFillColor (0f, 0f, 1f, 1f);
//Set the drawing mode back to something that will actually draw Fill for example
ctx.SetTextDrawingMode (CGTextDrawingMode.Fill);
//Set the text rotation to 90 degrees - Vertical from bottom to top.
ctx.TextMatrix = CGAffineTransform.MakeRotation ((float)(360 * 0.01745329f));
//Draw the text at the center of the image.
ctx.ShowTextAtPoint (2, 2, text);
tt = ctx.ToImage ();
}
}
//Return the image
return UIImage.FromImage (tt);
} catch (Exception ex) {
return new UIImage (Path.Combine (NSBundle.MainBundle.BundleUrl.ToString ().Replace ("%20", " ").Replace ("file://", ""), "images2.png"));
}
}
the output i am getting as following
As you can see it gets completely stretched in terms of width, i need this to be solved Any suggestions ???
At the same time the original image has nothing in the upper part, where as after processing it shows multi coloured layer, how to fix that ??
Why do you not draw your text directly to the image? Perhaps you can try this:
private static UIImage PutTextOnImage(UIImage image, string text, float x, float y)
{
UIGraphics.BeginImageContext(new CGSize(image.Size.Width, image.Size.Height));
using (CGContext context = UIGraphics.GetCurrentContext())
{
// Copy original image
var rect = new CGRect(0, 0, image.Size.Width, image.Size.Height);
context.SetFillColor(UIColor.Black.CGColor);
image.Draw(rect);
// Use ScaleCTM to correct upside-down imaging
context.ScaleCTM(1f, -1f);
// Set the fill color for the text
context.SetTextDrawingMode(CGTextDrawingMode.Fill);
context.SetFillColor(UIColor.FromRGB(255, 0, 0).CGColor);
// Draw the text with textSize
var textSize = 20f;
context.SelectFont("Arial", textSize, CGTextEncoding.MacRoman);
context.ShowTextAtPoint(x, y, text);
}
// Get the resulting image from context
var resultImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return resultImage;
}
The above method draws your text at coords x, y with given color and textsize. If you want it vertically you need to rotate the text with rotateCTM. keep in mind rotateCTM uses radius.
Add this to your using Context block (before DrawTextAtPoint):
var angle = 90;
var radius = 90 * (nfloat)Math.PI / 180;
context.RotateCTM(radius);

Starling + Box2d - Collision not precise

I create stage walls and a box inside on my mobile app using starling + as3.
Ok, now when I test the app the box falls but it does not match the walls, as if there
was an offset:
https://www.dropbox.com/s/hd4ehnfthh0ucfm/box.png
Here is how I created the boxes (walls and the box).
It seems like there is an offset hidden, what do you think?
public function createBox(x:Number, y:Number, width:Number, height:Number, rotation:Number = 0, bodyType:uint = 0):void {
/// Vars used to create bodies
var body:b2Body;
var boxShape:b2PolygonShape;
var circleShape:b2CircleShape;
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.shape = boxShape;
fixtureDef.friction = 0.3;
// static bodies require zero density
fixtureDef.density = 0;
var quad:Quad;
bodyDef = new b2BodyDef();
bodyDef.type = bodyType;
bodyDef.position.x = x / WORLD_SCALE;
bodyDef.position.y = y / WORLD_SCALE;
// Box
boxShape = new b2PolygonShape();
boxShape.SetAsBox(width / WORLD_SCALE, height / WORLD_SCALE);
fixtureDef.shape = boxShape;
fixtureDef.density = 0;
fixtureDef.friction = 0.5;
fixtureDef.restitution = 0.2;
// create the quads
quad = new Quad(width, height, Math.random() * 0xFFFFFF);
quad.pivotX = 0;
quad.pivotY = 0;
// this is the key line, we pass as a userData the starling.display.Quad
bodyDef.userData = quad;
//
body = m_world.CreateBody(bodyDef);
body.CreateFixture(fixtureDef);
body.SetAngle(rotation * (Math.PI / 180));
_clipPhysique.addChild(bodyDef.userData);
}
The SetAsBox method takes half width and half height as its parameters. I'm guessing your graphics don't match your box2d bodies. So either you will need to make your graphics twice as big or multiply your SetAsBox params by 0.5. Also the body pivot will be in the center of it, so offset your movieclip accordingly depending on its pivot position.
Note that box2d has a debugrenderer which can outline your bodies for you to see what's going on.

Update Widgets in PDF using Podofo

I am using PdfAnnotation.SetContents to set the value of an annotation.If the annotation is of type FreeText, only then this method correctly works and the value gets displayed on the PDF (using PDF Reader).If the type is Widget, the value gets set as content in pdf dictionary but does not get displayed.Is there a way i could set the value of a widget?
I found the solution, In order for the content to get displayed, an Appearance ("AP") Dictionary has to be set.
This could be used for that:
void PdfField::CreateFieldAppearance(PdfMemDocument *memDoc, const PdfString &value)
{
if( !m_pWidget->HasAppearanceStream() )
{
PdfRect pageRect;
PdfPainter painter;
PoDoFo::PdfRect rect = this->GetWidgetAnnotation()->GetRect();
unsigned int width = rect.GetWidth();
unsigned int height = rect.GetHeight();
PdfRect pdfRect(0, 0, width, height);
PdfXObject xObj(pdfRect, memDoc);
painter.SetPage(&xObj);
painter.SetClipRect(pdfRect);
painter.Save();
painter.SetColor(221.0/255.0, 228.0/255.0, 1.0);
painter.FillRect(0, 0, width, height);
painter.Restore();
// make rotation
painter.Save();
/***********************************************************************************/
// Rotation Logic
double angle = this->GetPage()->GetRotation();
if (angle) {
double radAngle = angle * M_PI / 180;
int cosA = (int)cos(radAngle);
int sinA = (int)sin(radAngle);
double translateY = rect.GetWidth(); // The View goes out of the bound, sits on top
painter.SetTransformationMatrix(cosA, sinA, -sinA, cosA, translateY, 0);
}
/***********************************************************************************/
PdfFont *font = memDoc->CreateFont("Helvetica", true, false);
font->SetFontSize(15);
// Do the drawing
painter.SetFont(font);
painter.BeginText(10, 5);
painter.SetStrokeWidth(20);
painter.AddText(value);
painter.EndText();
painter.FinishPage();
// This is very important. Not only does it disable the editing.
// Also it does correct the appearance issue on Adobe Readers.
this->SetReadOnly(true);
// The Stream Object has to be saved to the annotation
PoDoFo::PdfDictionary dict;
dict.AddKey( "N", xObj.GetObject()->Reference() );
this->GetFieldObject()->GetDictionary().AddKey( "AP", dict );
}
}

Resources