svg text-centering anomaly - javascript

I need to set SVG parameter text-anchor:"middle" for a set of single character tspan elements centered in small circles for a guitar chord chart generator: see http://chordography.blogspot.co.uk/.
When I paste the svg code into a browser: Chrome, IE, Firefox, Opera, Safari, or in Open Office Writer, the characters are placed left of centre, EXCEPT for the last tspan element, which is centered correctly. The last one is always OK, even if I rearrange the tspans. The problem may not be noticeable in most cases, but sticks out like a sore thumb in this application.
Here, the plot thickens. When I insert the svg code directly into the DOM with JavaScript, as is normal in Chordography, all tspan elements centre correctly. And there is one more twist; when I paste the code in Blogger, it also centres properly, as shown at http://chordography.blogspot.co.uk/p/blog-page_58.html.
Here is the code for the relevant parts derived from XMLSerializer, showing the locations of the circles and inset 'labels'. Only the final '1' is properly centered, along with the final 'A' in the footer.
<g class="dots">
<circle cx="62.1" cy="73.6" r="9.6"/>
<circle cx="85.1" cy="128.8" r="9.6"/>
<circle cx="108.1" cy="128.8" r="9.6"/>
<circle cx="131.1" cy="128.8" r="9.6"/>
<circle cx="154.1" cy="73.6" r="9.6"/>
</g>
<g text-anchor="middle" class="text">
<text class="labels">
<tspan x="62.1" y="79.2">1</tspan>
<tspan x="85.1" y="134.4">2</tspan>
<tspan x="108.1" y="134.4">3</tspan>
<tspan x="131.1" y="134.4">4</tspan>
<tspan x="154.1" y="79.2">1</tspan>
</text>
<text class="footer">
<tspan x="39.1" y="189.6"> </tspan>
<tspan x="62.1" y="189.6">D</tspan>
<tspan x="85.1" y="189.6">A</tspan>
<tspan x="108.1" y="189.6">D</tspan>
<tspan x="131.1" y="189.6">F♯</tspan>
<tspan x="154.1" y="189.6">A</tspan>
</text>
</g>
All a bit bizarre; any ideas anyone.

If you add 'text-anchor="middle"' to each tspan you will center them (you have to remove the space between the 'tspans' as well, otherwise the extra space will be considered as part of the first line and they won't be completely centered).
The space is most likely the reason you are having this issue.
The tspans look like this ...
<tspan text-anchor="middle" x="56.5" y="72">1</tspan><tspan
text-anchor="middle" x="77.5" y="122">2</tspan><tspan
text-anchor="middle" x="98.5" y="122">3</tspan><tspan
text-anchor="middle" x="119.5" y="122">4</tspan><tspan
text-anchor="middle" x="140.5" y="72">1</tspan>
Reference jsFiddle: http://jsfiddle.net/rfornal/0u5wmevm/

Usually I'd regex all unwanted characters, then read string as array, eg:
var badStr = 'xx,1p23,4 "5'; // string with errors
var newStr = str.replace(/[^x\d]/g,''); // outputs: x12345
console.log(newstr[1]); // debug, outputs: 1

Related

How would I add custom SVG shapes to an equation generated with MathJax?

I'd like to use MathJax to write various equations that include SVG shapes along the lines of the following:
(2 * [red box]) + [red box] = [three red boxes]
Where each item in brackets would be a custom SVG element defined in the HTML ranging from simple (a single box) to more complex (multiple shapes). The reason for needing this is that I want to use MathJax's ability to format math equations while replacing some symbols with SVG shapes. I may need to specify other HTML as well.
I suspect this can be achieved by using MathJax's HTML snippets but I don't know how to take the sample code they provide and make it work for any given equation.
Any help would be greatly appreciated.
If you are using MathML input, you can use the <mglyph> element to include an svg image into your expression, as in:
<math>
<mglyph src="dice.svg" height="42px" width="42px" valign="-14px" alt="Dice showing five dots"></mglyph>
</math>
or even
<math>
<mglyph src='data:image/svg+xml,
<svg xmlns="http://www.w3.org/2000/svg" height="42px" width="42px">
<rect stroke="black" fill="none" x="1px" y="1px" stroke-width="2px" rx="5px" width="40px" height="40px"></rect>
<circle stroke="black" fill="black" cy="30px" cx="30px" r="5px"></circle>
<circle stroke="black" fill="black" cy="30px" cx="10px" r="5px"></circle>
<circle stroke="black" fill="black" cy="20px" cx="20px" r="5px"></circle>
<circle stroke="black" fill="black" cy="10px" cx="30px" r="5px"></circle>
<circle stroke="black" fill="black" cy="10px" cx="10px" r="5px"></circle>
</svg>'
valign="-14px"
alt="Dice showing five dots">
</mglyph>
</math>
If you are using TeX input, you can create the mglyph using the \mmlToken macro:
\mmlToken{mglyph}[src="dice.svg" width="42px" height="42px" valign="-14px" alt="Dice showing five dots"]{}
You can also use the "img" extension from the third-party extension library. This defines an \img macro that makes loading the image a bit easier:
\img[-14px][42px][42px]{dice.svg}
I think you should be able to do what you want using one of those.
(This is my response to the cross-post on the MathJax User's Forum)

Printing an inline SVG (in mm) from browser

I have to print my SVG straight from the browser, but I have no idea how to do that.
The locations and sizes of the SVG's elements are important, that's why the numbers are all in mm.
It has to print on pre-printed paper, in pre-printed containers.
The SVG currently looks something like this:
<svg xmlns="http://www.w3.org/2000/svg" class="col-md-12 designerCanvas" id="svgLabel" width="240mm" height="90mm" viewbox="0 0 240 90">
<image class="svg" id="img-160-68" visibility="visible" x="160.202" y="68.0135" width="14.0043" height="14.0043" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/images/Icons/icon02.png" />
<image class="svg" id="img-175-68" visibility="visible" x="175.791" y="68.0135" width="14.0043" height="14.0043" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/images/Icons/icon05.png" />
<image class="svg" id="img-191-68" visibility="visible" x="191.381" y="68.0135" width="14.0043" height="14.0043" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/images/Icons/icon07.png" />
<text class="svg" id="txt-0-5" font-family="Arial" font-size="1.64233" visibility="visible" text-anchor="start" x="0.5285" y="5.5489" height="33.29333142498542" width="79.26983672615574">
<tspan x="0.5285" dy="1.6423">[EN] Some Title: </tspan>
<tspan x="0.5285" dy="1.6423">There is some text here.</tspan>
<tspan x="0.5285" dy="1.6423">Even more text here. </tspan>
<tspan x="0.5285" dy="1.6423">WOW, a third line.</tspan>
<tspan x="0.5285" dy="1.6423">You're overdoing it</tspan>
<tspan x="0.5285" dy="1.6423">Please</tspan>
<tspan x="0.5285" dy="1.6423">STAHP</tspan>
<tspan x="0.5285" dy="1.6423">No More!!</tspan>
<tspan x="0.5285" dy="1.6423">That's it</tspan>
<tspan x="0.5285" dy="1.6423">I'm outta here....</tspan>
</text>
</svg>
Do note that the paper's (=SVG canvas) width and height come from the DB and can have several values.
The x, y, width and height of the elements now don't have mm, as the viewbox and units combo of the SVG canvas solve that, though I can add it if needed.
Client only wants me to support IE11+, though I myself want to support recent Chrome and FF as well.
I could load the drawing in a fresh (temporary) window to print it, though I'm not sure it'll print on the correct coördinates like that.
Maybe creating a PDF and print that is the way to go, though no idea how to send the svg to that.
The web application itself is an ASP.NET MVC (Core), with plain javascript and jQuery added to the front end.
Couldn't find much info on the web on the topic, besides printing a SVG in pixels on default paper, but I'm pretty sure the elements will get printed in the wrong location/size that way.
Any ideas?

How does "text-align: justify" works?

Hello I am writing a lib. for creating composition of texts, internal customisation. - d3-fusiontext.
I want to support
text-align: Justify
The user say provides me a long text. Mentions the height and width it would like to be rendered. The lib. wraps it up, and provides a good visual with wrapped texts. They are all svg text elements so that it can be exported too.
Now I would be to curious to know how the browser internally aligns in a justified manner? Any source/ links/ topics to start with. Any help/ guidance is highly appreciated.
This is a good example of how things might look.
codepen.io/anon/pen/zxNJKE
P.S: Sorry about no gh-pages and docs as the stuff is under dev. Will update.
Just a generalized curiosity how does the browser determines the spacings in justified alignment?
There are other answers on SO which provide information on how you can do text wrapping.
Word Wrap in Raphael JS / SVG
How to either determine SVG text box width, or force line breaks after 'x' characters?
Once you work out which characters/words fit on the line, you can use the textLength and lengthAdjust attributes to get SVG to stretch the line to fit the width.
<svg width="10cm" height="3cm" viewBox="0 0 1000 300"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="200" y1="0" x2="200" y2="300" stroke="red"/>
<line x1="800" y1="0" x2="800" y2="300" stroke="red"/>
<text x="200" y="100"
font-family="Verdana" font-size="55" fill="blue" >
Hello, out there
</text>
<text x="200" y="170"
font-family="Verdana" font-size="55" fill="blue"
textLength="600" lengthAdjust="spacing">
Hello, out there
</text>
<text x="200" y="240"
font-family="Verdana" font-size="55" fill="blue"
textLength="600" lengthAdjust="spacingAndGlyphs">
Hello, out there
</text>
<!-- Show outline of canvas using 'rect' element -->
<rect x="1" y="1" width="998" height="298"
fill="none" stroke="blue" stroke-width="2" />
</svg>

D3.js Text on path not rendered (no height / width)

I am trying to render circles which have a text inside, that runs along a given path.
The markup d3 produces looks fine, but Chrome is not showing the texts.
Upon inspection it says text elements have 0 width and 0 height.
This is sample markup including only two circles:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 950 600">
<g>
<g transform="translate(334.14792673070184,58.96385042366173)">
<defs>
<path id="path-1" d="m5,50 a45,45 0 0 0 90,0"></path>
</defs>
<circle class="circle" fill="#ccc" cx="50" cy="50" r="50"></circle>
<text fill="#333" font-size="15px">
<textpath xlink:href="#path-1" start-offset="0%">123456</textpath>
</text>
<use xlink:href="#path-1" fill="#666" opacity="0.1"></use>
</g>
</g>
<g transform="translate(374.66047394649974,371.7948729806046)">
<defs>
<path id="path-2" d="m5,50 a45,45 0 0 0 90,0"></path>
</defs>
<circle class="circle" fill="#ccc" cx="50" cy="50" r="50"></circle>
<text fill="#333" font-size="15px">
<textpath xlink:href="#path-2" start-offset="0%">123456</textpath>
</text>
<use xlink:href="#path-2" fill="#666" opacity="0.1"></use>
</g>
</svg>
When I inspect the markup in Chrome console and click "Edit as HTML" on the SVG element, make a random change, save & exit - the SVG suddenly renders correctly.
The exact same thing happens in Firefox and Opera.
Copy pasting the generated markup into a jsfiddle renders everything as expected.
I have tried pulling the < defs > tags out of each individual group into a single global < defs > but it did not solve the problem.
I have also looked at user-agent-stylesheet and other CSS rules that might interfere with rendering.
Is this a problem with how the SVG tag is included and/or the container element's width/height properties? I have been trying different things to fix this for a couple of hours now...
Here is the full SVG markup http://pastebin.com/J2Lz8p23
Here are the relevant parts in my code http://pastebin.com/Bym8kJVN

Making a D3 widget scrollable

I'm sticking a D3 tree widget into my web app. It grows children and appends them to the tree. However, when the tree gets to be too big, it starts to go off the page. That's fine since I don't want to the individual tree nodes to get too small, but it would be nice if I could add a scroll bar. However, I've tried doing it the normal way, overflow: auto, but it doesn't work. Maybe it's something to do with the D3 svg stuff.
Here's the code for a tree with 2 nodes:
<div id="Graph">
<svg width="100%" height="10%" id="SVG" overflow="auto" display="block">
<g transform="translate(40,0)">
<path class="link" d="M0,20C213.75,20 213.75,20 427.5,20"></path>
<g class="node" transform="translate(427.5,20)">
<circle r="4.5" style="fill: rgb(255, 255, 255);"></circle>
<text x="10" dy=".35em" text-anchor="start" style="fill-opacity: 1;">1</text>
</g>
<g class="node" transform="translate(0,20)">
<circle r="4.5" style="fill: rgb(255, 255, 255);"></circle>
<text x="-10" dy=".35em" text-anchor="end" style="fill-opacity: 1;">0</text>
</g>
</g>
</svg>
</div>
Once it gets to be more than around 10 or 11 nodes, it goes off the screen. How can I fix this?
Make the width of the svg element > 100%. That will overflow the div and the div will be scrollable. You might also need to set the overflow style to scroll on the <div>

Categories