Hebrew text on SVG textPath reversed only in Safari - svg

When putting Hebrew text on an SVG textPath it is reversed only in Safari (macOS ventura 13.2 Safari 16.3). It is OK in Firefox and Chrome. Text that is NOT on a path is always OK. Furthermore, I am able to use bidi-override to reverse the text in Firefox/Chrome, but in Safari that did not un-reverse the reversed text as I expected (and even if it did that would not be a cross-browser solution). I also tried playing with various rtl/ltr css/html/svg dir/direction settings as well as lang/xml:lang he. I can of course reverse the text string in advance for Safari, but I am looking for a cross-browser solution.
This is a similar question, but the author is not addressing the browser-specific issue (I think at the time it was also broken in Chrome so he could just reverse the string in advance for both), and the accepted answer is not offering a concrete explanation nor is it helpful practically: RTL text (Hebrew) shows reversed when is on SVG path
Chrome:
Safari:
<html dir="rtl" lang="he">
<svg viewBox="0 0 1000 1000" width=500" xmlns="http://www.w3.org/2000/svg">
<path
id="MyPath1"
fill="none"
stroke="red"
d="M 500, 120 m 0, -110 a 110,110 0 0,1 0,320 a 110,110 0 0,1 0,-320" />
<path
id="MyPath2"
fill="none"
stroke="green"
d="M 200, 120 m 0, -110 a 110,110 0 0,1 0,320 a 110,110 0 0,1 0,-320" />
<text x='600' y='200'>
text not on path is ok טקסט רגיל
</text>
<text>
<textPath href="#MyPath1" text-anchor="end">hebrew textpath reversed only on safari טקסט על מסלול הפוך רק בספארי</x>
</text>
<text unicode-bidi="bidi-override" direction="ltr">
<textPath href="#MyPath2">טקסט על מסלול הפוך תמיד hebrew textpath always reversed</textPath>
</text>
</svg>
</html>
codepen: https://codepen.io/eyaler/pen/VwBBOXz?editors=1011

Got it! Since Safari is just ignoring all bidi stuff on textPath, that is, both the logical direction and the bidi-override, I can just reverse the string in advance AND do unicode-bidi="bidi-override" direction="ltr"! Double negatives to the rescue! This is a cross-browser solution.
<html dir="rtl" lang="he">
<svg viewBox="0 0 1000 1000" width=500" xmlns="http://www.w3.org/2000/svg">
<path
id="MyPath1"
fill="none"
stroke="red"
d="M 500, 120 m 0, -110 a 110,110 0 0,1 0,320 a 110,110 0 0,1 0,-320" />
<path
id="MyPath2"
fill="none"
stroke="green"
d="M 200, 120 m 0, -110 a 110,110 0 0,1 0,320 a 110,110 0 0,1 0,-320" />
<text x='600' y='200'>
text not on path is ok טקסט רגיל
</text>
<text>
<textPath href="#MyPath1" text-anchor="end">hebrew textpath reversed only on safari טקסט על מסלול הפוך רק בספארי</x>
</text>
<text unicode-bidi="bidi-override" direction="ltr">
<textPath href="#MyPath2">רדסב גצומו רוקמב יתכפהש לולסמ לע טסקט hebrew textpath hardcoded reversed to display ok on all browsers</textPath>
</text>
</svg>
</html>

Related

SVG: Unexpected pixel in stroke-dasharray at start corner of rect

I'd like to draw a rectangle with a top and bottom border (as part of a database-flow diagram). Therefore, I use stroke-dasharray on rect like this:
<svg viewBox="-64 -24 178 73" xmlns="http://www.w3.org/2000/svg">
<rect stroke-dasharray="50 25" width="50" height="25" fill="none"
stroke="black"></rect>
<text x="25" y="13" text-anchor="middle" dominant-baseline="central"
font-size="10px" fill="#414141">Database
</text>
</svg>
If you look closely at the top left corner of the rendered rectangle, you should see a notch (highlighted by the magenta circle). This pixel is not rendered in the other corners of the rectangle (highlighted by the green vertical line):
I expect
no notch
that the top line has the same length as the bottom line
that the top and bottom line start at the same x-position in the rendered image
That means, I expect the image to look like this (without the magenta circle and green line)
How to fix my SVG to look like this? Can this be done with stroke on rect? Why is the notch/pixel added in the first place?
Edit: I have this issue on Linux in Google Chrome Version 95.0.4638.69 and Firefox 94.0, but it seems to be a bug (see comments).
That seems to be a firefox bug- looks fine in Chrome/Win. If you convert your rect to a path, it works fine.
<svg viewBox="-64 -24 178 73" xmlns="http://www.w3.org/2000/svg">
<path d="M 0 0 h50 v 25 h-50 v-25" stroke-dasharray="50 25" fill="none"
stroke="black"></path>
<text x="25" y="13" text-anchor="middle" dominant-baseline="central"
font-size="10px" fill="#414141">Database
</text>
</svg>
#MichaelMullany has given a workaround.(https://stackoverflow.com/a/70054910/1065654). Alternatively, you can use stroke-linecap="square" to extend the line and cover the notch
<svg viewBox="-64 -24 178 73" xmlns="http://www.w3.org/2000/svg">
<rect stroke-dasharray="50 25" width="50" height="25" fill="none"
stroke="black" stroke-linecap="square"></rect>
<text x="25" y="13" text-anchor="middle" dominant-baseline="central"
font-size="10px" fill="#414141">Database
</text>
</svg>
Tested with Google Chrome Version 95.0.4638.69 on Linux.

Add svg icon in the middle of an svg curved line

I have a curved svg line like this
<path d="M70,260 C105,260 126,330 160,330"
style="stroke: #ff4444;stroke-width:2; fill:none;"/>
what I want is to add another svg (like https://www.flaticon.com/free-icon/play-button_149657) in the middle of my line pointing to the end point.
any ideas?
One way to achieve the result is a degenerate animation:
Define the marker shape (obj1 in the example below)
Position the marker at the beginning of the curve (track1 below; this is the path definition from your example).
Specify an animated motion of the marker shape along the curve with some particular settings:
Explicit positioning along the track using keyTimes, keyPoints attributes, limiting the range of positions to exactly one point: the midpoint of the curve
Infinite duration, infinite repeat
Auto-rotation of the shape according to the orientation of the track curve ( rotate attribute )
Effectively there is no animation at all but the shape is positioned at the center of the curve, properly oriented.
Example
<html>
<head>
<title>SVG object centered on path</title>
</head>
<body>
<svg width="200px" height="200px"
viewBox="0 0 500 500"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path
id="obj1"
d="M11.18,0 L-2.5,10 -2.5,-10 Z"
stroke="black" stroke-width="1" fill="green"
>
</path>
<path
id="track1"
d="M70,260 C105,260 126,330 160,330"
stroke="#ff4444" stroke-width="2" fill="none"
/>
</defs>
<use xlink:href="#track1"/>
<use xlink:href="#obj1">
<animateMotion
calcMode="linear"
dur="infinite"
repeatCount="infinite"
rotate="auto"
keyPoints="0.5;0.5"
keyTimes="0.0;1.0"
>
<mpath xlink:href="#track1"/>
</animateMotion>
</use>
</svg>
</body>
</html>
There are a number of ways to do this.
One way is to "cheat" a little and use a <textPath> and an arrow character.
SVG marker-mid on specific point on path
This is a little hacky, and may not work reliably on all browsers, but it may be good enough for your needs.
Another way is split the path in two (using De Casteljau's algorithm), and use a <marker>.
<svg viewBox="0 200 200 200" width="400">
<defs>
<marker id="Triangle"
viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="strokeWidth"
markerWidth="4" markerHeight="3"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path d="M 70,260
C 87.5,260 101.5,277.5 115.375,295
C 129.25,312.5 143,330 160,330"
style="stroke: #ff4444; stroke-width:2; fill:none; marker-mid:url(#Triangle)"/>
</svg>
There are other ways using Javascript. For example, you could use the SVGPathElement.getPointAtLength() method to find the coordinates of the centre of the path. Then position a triangle at that location.

svg draw circle with curved text inside

I need to draw red cirle with two curved string inside like that:
upper string always be 3 chars length
lower string can be from 1 to 20 chars length
UPDATE1:
I try to use textpath and circle tags, but I think I need to change some coordinates:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="40" cy="40" r="24" style="stroke:#006600; fill:none"/>
<defs>
<path id="myTextPath"
d="M75,20
a1,1 0 0,0 150,0"
/>
</defs>
<text x="5" y="50" style="stroke: #000000;">
<textPath xlink:href="#myTextPath" >
string
</textPath>
</text>
</svg>
Also I didnt clear understand <path> 'd' atrribute , but I found out that I can change starting point to M10,20 but how I can change text curve orientation?
d="M10,20 a1,1 0 0,0 150,0"
To have text that "hangs" from a line nicely, the best way right now is to use a path with a smaller radius. There is an attribute to adjust the text's baseline, but that doesn't work reliably.
So you need two arcs. One for the bottom half of the circle, and one with a smaller radius for the top half. They also need to both start from the left. That means one will go clockwise, and the other will go anti-clockwise. You control that with the arc command's "sweep" flag.
We need to also use startOffset="50%" and text-anchor="middle" to centre the text on the paths.
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 80 80">
<defs>
<path id="tophalf" d="M26,40 a14,14 0 0,1 28,0" />
<path id="lowerhalf" d="M16,40 a24,24 0 0,0 48,0" />
</defs>
<circle cx="40" cy="40" r="24" style="stroke:#006600; fill:none"/>
<path d="M16,40 a24,24 0 0,0 48,0" style="stroke:#600; fill:none"/>
<text x="5" y="50" style="stroke: #000000;"
text-anchor="middle">
<textPath xlink:href="#tophalf" startOffset="50%">str</textPath>
</text>
<text x="5" y="50" style="stroke: #000000;"
text-anchor="middle">
<textPath xlink:href="#lowerhalf" startOffset="50%">second st</textPath>
</text>
</svg>
This works fine in FF, but unfortunately, it seems there are bugs in Chrome and IE right now that is causing the text to not be centred properly on those browsers.

SVG Path rendering not consistent across browsers

I'm experiencing two different renderings of the same SVG path on two webkit browsers : Chrome and Safari.
Here is the markup :
<svg class="drillPath0" viewBox="0 0 775 310">
<path fill="transparent" stroke="#000" d="M 100 100 V 0"></path>
<path fill="transparent" stroke="#000" d="M 200 100 H 100"></path>
<path fill="transparent" stroke="#000" d="M 200 100 V 200"></path>
</svg>
On Chrome, it properly starts from the top of the SVG element.
On Safari, it has a 100px offset.
There is a jsFiddle ready if needed.
This happened to be a Safari bug, that has been fixed with the 7.0.1 update and iOS 8.

Fill polygon with pattern doesn't work with leaflet

I try to render a SVG polygon filled with pattern. SVG.path filled with pattern doesn't work. As you can see in this jsfiddle, filled background shows up transparent in Firefox and black in Chrome.
The example is based on leaflet GeoJSON Example and uses the diagonalHatch pattern described by carto.net.
<defs>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" x="0" y="0" width="105" height="105">
<g style="fill:none; stroke:black; stroke-width:1">
<path d="M0 90 l15,15"/><path d="M0 75 l30,30"/>
<path d="M0 60 l45,45"/><path d="M0 45 l60,60"/>
<path d="M0 30 l75,75"/><path d="M0 15 l90,90"/>
<path d="M0 0 l105,105"/><path d="M15 0 l90,90"/>
<path d="M30 0 l75,75"/><path d="M45 0 l60,60"/>
<path d="M60 0 l45,45"/><path d="M75 0 l30,30"/>
<path d="M90 0 l15,15"/>
</g>
</pattern>
</defs>
As this jsfiddle shows, copying the SVG polygons below the map, makes it work on Chrome but not on Firefox. Apply a fill pattern adding this style to SVG.path:
style="fill: url(#diagonalHatch)"
I'm really not sure if this is a bug in leaflet or some conflict with SVG implementation on Firefox and Chrome.
I've wrote a leaflet plugin for this, you may try it,
https://github.com/lnaweisu/leaflet-polygon-fillPattern
Maybe you can try setting the path via the shape's attribute as mentioned in this thread: Leaflet polygon with fuzzy outline
// Set filter attribute on the polygon
polygon._path.setAttribute('filter', 'url(#blur)');

Resources