Is there a way to add text using Paths Drawing
With MKOverlayPathView
, I think the easiest way to add text is to override drawMapRect:zoomScale:inContext:
and put the path and text drawing there (and do nothing in or don't implement createPath
).
But if you're going to use drawMapRect
anyway, you might want to just switch to subclassing a plain MKOverlayView
instead of MKOverlayPathView
.
With an MKOverlayView
, override the drawMapRect:zoomScale:inContext:
method and draw the circle using CGContextAddArc
(or CGContextAddEllipseInRect
or CGPathAddArc
).
You can draw the text using drawAtPoint
in this method which will have the required context
.
For example:
-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
//calculate CG values from circle coordinate and radius...
CLLocationCoordinate2D center = circle_overlay_center_coordinate_here;
CGPoint centerPoint =
[self pointForMapPoint:MKMapPointForCoordinate(center)];
CGFloat radius = MKMapPointsPerMeterAtLatitude(center.latitude) *
circle_overlay_radius_here;
CGFloat roadWidth = MKRoadWidthAtZoomScale(zoomScale);
//draw the circle...
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextSetFillColorWithColor(context, [[UIColor blueColor] colorWithAlphaComponent:0.2].CGColor);
CGContextSetLineWidth(context, roadWidth);
CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, 0, 2 * M_PI, true);
CGContextDrawPath(context, kCGPathFillStroke);
//draw the text...
NSString *text = @"Hello";
UIGraphicsPushContext(context);
[[UIColor redColor] set];
[text drawAtPoint:centerPoint
withFont:[UIFont systemFontOfSize:(5.0 * roadWidth)]];
UIGraphicsPopContext();
}
In relation to a comment in another answer...
When the center coordinate or radius (or whatever) of the associated MKOverlay
changes, you can make the MKOverlayView
"move" by calling setNeedsDisplayInMapRect:
on it (instead of removing and adding the overlay again). (When using a MKOverlayPathView
, you can call invalidatePath
instead.)
When calling setNeedsDisplayInMapRect:
, you can pass the boundingMapRect
of the overlay for the map rect parameter.
In the LocationReminders sample app from WWDC 2010, the overlay view uses KVO to observe changes to the associated MKOverlay
and makes itself move whenever it detects a change to the circle's properties but you could monitor the changes in other ways and call setNeedsDisplayInMapRect:
explicitly from outside the overlay view.
(In a comment on another answer I did mention using MKOverlayPathView
and that is how the LocationReminders app implements a moving circle overlay view. But I should have mentioned how you can also use MKOverlayView
to draw a circle. Sorry about that.)
Add text to the path
Is it possible to add text to the current path, e.g. for clipping?
The simple answer is no, text paths are not exposed to us through canvas context so we cannot use them for things such as clipping.
The only way is either to:
- Use composite mode to "punch" a hole for the text. Works much in the same way as clipping but is related to mattes more than paths.
- Extract the text paths from fonts as polygons manually and use that with line, Bezier etc. A library that can help extract font paths could be opentype.js.
How can I draw text on a path in Jetpack Compose?
We use nativeCanvas
to draw a text using Path
in Compose, like how we do normally in Custom Views.
Ex:
@Composable
fun ArcTextExample() {
val paint = Paint().asFrameworkPaint()
Canvas(modifier = Modifier.fillMaxSize()) {
paint.apply {
isAntiAlias = true
textSize = 24f
typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)
}
drawIntoCanvas {
val path = Path()
path.addArc(RectF(0f, 100f, 200f, 300f), 270f, 180f)
it.nativeCanvas.drawTextOnPath("Hello World Example", path, 0f, 0f, paint)
}
}
}
Note:
we should use android.graphics.Path
And the result will be like:
Properly draw text using GraphicsPath
Seems you are providing wrong measure for font size in the first place and then adding extra thickness to the brush. Try this instead:
using (GraphicsPath path = new GraphicsPath())
{
path.AddString(
text,
_fontStyle.FontFamily,
(int)_fontStyle.Style,
e.Graphics.DpiY * fontSize / 72f, // em size
new Point(0, 0), // location where to draw text
string_format);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
e.Graphics.DrawPath(new Pen(Color.Red), path);
}
Drawing a path with subtracted text using Core Graphics
Here's some code I ran and tested that will work for you. See the inline comments for details:
Update: I've removed the manualYOffset:
parameter. It now does a calculation to center the text vertically in the circle. Enjoy!
- (void)drawRect:(CGRect)rect {
// Make sure the UIView's background is set to clear either in code or in a storyboard/nib
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor whiteColor] setFill];
CGContextAddArc(context, CGRectGetMidX(rect), CGRectGetMidY(rect), CGRectGetWidth(rect)/2, 0, 2*M_PI, YES);
CGContextFillPath(context);
// Manual offset may need to be adjusted depending on the length of the text
[self drawSubtractedText:@"Foo" inRect:rect inContext:context];
}
- (void)drawSubtractedText:(NSString *)text inRect:(CGRect)rect inContext:(CGContextRef)context {
// Save context state to not affect other drawing operations
CGContextSaveGState(context);
// Magic blend mode
CGContextSetBlendMode(context, kCGBlendModeDestinationOut);
// This seemingly random value adjusts the text
// vertically so that it is centered in the circle.
CGFloat Y_OFFSET = -2 * (float)[text length] + 5;
// Context translation for label
CGFloat LABEL_SIDE = CGRectGetWidth(rect);
CGContextTranslateCTM(context, 0, CGRectGetHeight(rect)/2-LABEL_SIDE/2+Y_OFFSET);
// Label to center and adjust font automatically
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, LABEL_SIDE, LABEL_SIDE)];
label.font = [UIFont boldSystemFontOfSize:120];
label.adjustsFontSizeToFitWidth = YES;
label.text = text;
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
[label.layer drawInContext:context];
// Restore the state of other drawing operations
CGContextRestoreGState(context);
}
Here's the result (you can change the background to anything and you'll still be able to see through the text):
Add text label to drawn shape
In your drawRect
implementation you can draw the coordinates of the view with something like:
("\(frame.origin.x), \(frame.origin.y)" as NSString).drawAtPoint(.zero, withAttributes: [
NSFontAttributeName: UIFont.systemFontOfSize(14),
NSForegroundColorAttributeName: UIColor.blackColor()
])
Which simply creates a string of the coordinates, casts it to an NSString
and then calls the drawAtPoint
method to draw it in the view's context.
You can of course change .zero
to any CGPoint
depending on where you want to draw the string and can edit the attributes as desired.
To make sure that this gets updated when the user pans around you will want to also add:
self.setNeedsDisplay()
to the bottom of your didPan
method.
Hope this helps :)
Draw text around QPainterPath efficiently
There is no built-in method to draw a text following a path.
But, if QPainter
is not efficient enough, you can gain some perfs by building a new path with your text and by drawing after your loop (you will not use QPainter::save()
and QPainter::restore()
in a loop):
void paintEvent(QPaintEvent* event)
{
QString text = "Short text";
text = text.repeated(1000); // Check with a very long text
QPainterPath rawPath;
rawPath.addEllipse(QRect(0, 0, 200, 200));
QPainterPath path;
double const step = 1.0 / double(text.length());
double percent = 0.0;
for(QChar const& c: text)
{
double angle = rawPath.angleAtPercent(percent);
QPointF point = rawPath.pointAtPercent(percent);
QTransform mat;
mat.rotate(-angle);
QPainterPath p2;
p2.addText(0, 0, font(), c);
p2 = mat.map(p2);
path.addPath(p2.translated(point));
percent += step;
}
QPainter painter(this);
painter.drawPath(path.translated(100, 100));
}
Related Topics
How to Get the Front Camera in Swift
Having App Restart Itself When It Detects Change to Privacy Settings
Launch Other Application Without Url Schema in Iphone
Nsnumberformatter with Comma Decimal Separator
Exit Application When Click Button - iOS
Swift Invalidate Timer Doesn't Work
Detect Touch on Child Node of Object in Spritekit
How to Get a Crash Log Due to Expiration of Provisioning Profile
Switching Between Text Fields on Pressing Return Key in Swift
Main.Async VS Main.Sync() VS Global().Async in Swift3 Gcd
Simulate Universal Gravitation for Two Sprite Kit Nodes
Why Would a 'Scheduledtimer' Fire Properly When Setup Outside a Block, But Not Within a Block
How to Pass Information Between Storyboard Segues
Setting Image for Uibarbuttonitem - Image Stretched