Knockout's HTML binding + SVG - javascript

I'm using Knockout to render dynamic SVG's by passing strings into an SVG data-bound with the html: binding. In Chrome this works perfectly. In Firefox it will set up the DOM correctly (i.e. I can see that the child svg elements are present in firebug) but the graphic itself is not displayed.
I made a fiddle: https://jsfiddle.net/4eTJL/1/ but interestingly, the Firefox behavior shows in both browsers in the fiddle.

<svg> tag has no innerHTML property, that's why ko html binding doesn't work, but you can avoid this problem by putting all svg content inside logo variable, then bind it to a standard html tag.
https://jsfiddle.net/4eTJL/2/
<div data-bind="html: logo"></div>
var vm = {
logo: '<svg viewBox="0 0 50 50" class="center-block" xmlns="http://www.w3.org/2000/svg" width="80" height="80" data-bind="xml: logo"><rect ry="8" rx="8" id="svg_2" height="50" width="50" y="0" x="0" stroke-width="5" fill="#bfbfbf"></rect><text font-family="Graduate" textLength="40" lengthAdjust="spacingAndGlyphs" text-anchor="middle" x="25" y="37" font-size="33" fill="crimson" stroke="black" stroke-width="1.25">NO</text></svg>'
};
ko.applyBindings(vm);

Related

SVG Pattern element wont resize in Chrome

I'm using inline svgs. I have a svg circle and fill it with a pattern. The image inside needs to 100% of container size. This works until the parent element gets resized.
When the parent element(div) gets resized via js the pattern wont reflect 100% width and height anymore.
This works in Firefox though.
To me it seems like the css doesnt get updated. If I change the value to 99% manually Chrome updates the size on both dimensions.
This is the structure of my svg:
<div style="height:150px; width:150px;">
<svg style="height:100%; width:100%;">
<defs>
<pattern id="image" x="0%" y="0%" width="100%" height="100%">
<image x="0%" y="0%" width="58%" height="58%" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="image.jpg"></image>
</pattern>
</defs>
<circle cx="50%" cy="50%" r="29%" fill="url(#image)">
</circle>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#other"></use>
</svg>
<div>
I had found similar questions, but without help:
Image inside svg pattern is blurried after zoom in Chrome (there the image gets blurry)
SVG <pattern> won't load when generated by Javascript (the question got closed without a good answer)
You need to add viewBox property in svg, please refer the following link:
https://css-tricks.com/scale-svg/
Updated Code -
function inc(){
var parent = document.getElementById('parent');
parent.style.width = '350px';
parent.style.height = '350px';
}
<div id='parent' style="height:150px; width:150px;">
<svg style="height:100%; width:100%;" viewBox="0 0 50 50">
<defs>
<pattern id="image" x="0%" y="0%" width="100%" height="100%">
<image x="0%" y="0%" width="58%" height="58%" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="image.jpg"></image>
</pattern>
</defs>
<circle cx="50%" cy="50%" r="29%" fill="url(#image)">
</circle>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#other"></use>
</svg>
<div>
Increase

Grouping elements in inline SVG disables getElementById() on group children

I have a simple SVG written directly in my HTML document. It contains one path with unique ID, originalPath. I can access that path directly by getElementById() like this:
HTML:
<svg id="previewImage" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="originalPath" d="" fill="none" stroke="black" stroke-width="1"></path>
</svg>
JS:
var svg = document.getElementById("previewImage");
var svgPath = svg.getElementById("originalPath");
// var svgPath = $("#originalPath")[0]; // Also working
However, if I wrap my originalPath in a group (directly in the HTML), the getElementById() function suddenly stops working, svgPath is undefined. The jQuery line doesn't work either.
<svg id="previewImage" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<path id="originalPath" d=""></path>
</g>
</svg>
I can't see what I'm doing wrong. I even tried accessing the group first and then its child, but without any success. Could someone point me in the right direction?

clip path selection Chrome vs. Firefox

The below selector will not find <clipPath> elements inside <defs> on Chrome (38):
d3.selectAll('defs clipPath')
(This is D3.js code but I suspect underlying querySelectorAll issue)
It works fine on Firefox. Is there a different selector syntax to use that will work on both browsers?
In the example below on Firefox you will see the whole text because the clip path is removed. But on Chrome it will be cut off after 85 pixels because the clip path is not removed.
d3.selectAll('defs clipPath').remove();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg height="200" width="400">
<defs>
<clipPath id="clip1">
<rect id='tt' x="0" y="0" width="85" height="15"></rect>
</clipPath>
</defs>
<text clip-path="url(#clip1)" x="0" y="15">This text should all be visible once we remove the clip-path</text>
</svg>
As Lars pointed out, this was a webkit bug, and now in Blink it still exists as Issue 237435: querySelectorAll unable to find SVG camelCase elements in HTML
So until it's fixed, using a class selector is probably the best workaround.
d3.selectAll('defs .clippy').remove();
d3.selectAll('defs .clippy').remove();
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg height="200" width="400">
<defs>
<clipPath id="clip1" class='clippy'>
<rect id='tt' x="0" y="0" width="85" height="15"></rect>
</clipPath>
</defs>
<text clip-path="url(#clip1)" x="0" y="15">This text should all be visible once we remove the clip-path</text>
</svg>

Simple SVG Grid not being shown in IE 10 and IE 11

I got this little SVG grid
<svg id="grid-svg" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="smallGrid" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 10 0 L 0 0 0 10" fill="none" stroke="#000000" stroke-width="0.7" />
</pattern>
<pattern id="grid" width="100" height="100" patternUnits="userSpaceOnUse">
<rect width="100" height="100" fill="url(#smallGrid)" />
</pattern>
</defs>
<rect x="-100%" y="-100%" width="200%" height="200%" fill="url(#grid)" />
</svg>
I got it in a template html. Because I don't want it to remain in the main page for a reason.
Then I just clone that piece of SVG, create a wrapper div, and append the grid-svg to it.
Then I apply the grid dynamically with jQuery.
It works for Chrome and Firefox, but it doesn't work for IE 10 and IE 11.
Do you know why?
Thanks.
I am using the SVG using D3.js and i had the same issue.
I wrote the below code to resolve the issue
$('#lineChartSVG g').remove();
$('#lineChartSVG path').remove();
here i am removing the previous g and path, replacing with the new one.
Keep your tags in the static content and then call the above code where you used your code. This should work
This was solved already, i was doing a jquery clone() to get it from the template, which is wrong. Now it works fine.

Creating a pattern element in svg using raphael

I have some pattern in svg that I applied to my rect, the code is like this
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" style="position:absolute; top:0px; left:0px">
<defs>
<rect id="unitsqr" fill="#DBDBDB" stroke="white" stroke-width="1px" x="0" y="0" width="12" height="12"/>
<pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse">
<use xlink:href="#unitsqr" />
</pattern>
</defs>
<rect fill="url(#grid)" x="0" y="0" width="100%" height="100%"/>
</svg>
I want to do some animation in raphael but also keep my grid , I don't get any clue on how to create a pattern in raphael and use it as a fill later. Is there a way to do that anyway?
When you do Element.attr("fill", "http://example.com/example.png") Raphaël creates a <pattern> element for you under-the-hood if the SVG backend is used. But there's no highlevel API support in Raphaël for creating and manipulating pattern fills. So, either you'll need to extend Raphaël or you can do it with plain js assuming you don't care about the VML fallback for IE8 and lower.
The correct syntax would be
Element.attr("fill" , "url(http://exmaple.com/example.png)") ;
You can do funky stuff like filling creating an image shaped like a circle or a path easily by creating an element using Raphael.path or Raphael.circle and setting the fill to a url.

Categories

Resources