I am trying to render a svg image with knockout, but it is not showing image after I successfully bound the viewmodel.
Here is the SVG
<svg width="500" height="500" style="border: solid 1px black">
<image id="img1" width="500" height="500"
data-bind="attr:{'xlink:href': image}"></image>
</svg>
Here is the knockout bindings,
<script>
var viewModel = function(data){
var self = this;
self.image = ko.observable(data.image)
};
var data = {image: "http://2.bp.blogspot.com/-cGeVTe2XeWU/VUEiQidIJKI/AAAAAAAACwU/UYzCrcNMMAk/s1600/comic.png"};
var vm = new viewModel(data);
ko.applyBindings(vm);
</script>
Anyway I checked the page source after executing this code. So the SVG image element in page source is
<image id="img1" width="500" height="500" data-bind="attr:{'xlink:href': image}" xlink:href="http://2.bp.blogspot.com/-cGeVTe2XeWU/VUEiQidIJKI/AAAAAAAACwU/UYzCrcNMMAk/s1600/comic.png"></image>
As you can see here, it is setting xlink:href correctly, but it is not showing on svg.
Do I need to refresh DOM somehow?
Simply how can I render SVG image using knockout?
Any help will be appreciated
xlink:href attribute needs to be there even with empty value to initialize the HTML svg image.
so image tag should be like Here is a demo and more info
<image id="img1" width="500" height="500" xlink:href=""
data-bind="attr:{'xlink:href': image}"></image>
SVG elements are not added to the DOM when you use an img element to display the image, therefore knockout.js is unable to bind to those elements. The answers to this question contain some solutions that might help you:
How do you access the contents of an SVG file in an <img> element?
Note: I get this solution from Stackoverflow.
Related
Let's say that I have an SVG file in my database:
<svg width="400" height="100">
<rect width="400" height="100"
style="fill:rgb(0,0,255);stroke-width:10;stroke:rgb(0,0,0)" />
</svg>
It looks like this
And in my React code I fetch the SVG file like so:
fetch('/api/picture')
.then(res => res.json())
.then(res => {
this.setState({
picture: res
})
})
So now in my state, I have a variable called picture whose value is this:
<svg width="400" height="100">
<rect width="400" height="100"
style="fill:rgb(0,0,255);stroke-width:10;stroke:rgb(0,0,0)" />
</svg>
After doing some research, the only way that I have found to render the SVG is this way:
<div>
<div dangerouslySetInnerHTML={{ __html: this.state.picture }}></div>
</div>
But I'm a little confused on whether this is the preferred and flexible way to do it.
If I want a button on my page where if I click it, the circle will turn red, how will I be able to do that with my current code? What about a button that will add another circle to the svg?
I know I have to access the rect in some way and change the style, but I cannot think of a way with the way I've set it up.
I tried looking for a solution but I can't seem to find one, so I'm under the impression that I have to render my SVG a different way. Could anyone help me figure this out? Thank you
I created https://github.com/hugozap/react-svgmt to facilitate SVG loading and manipulation:
You can load the SVG from a url or string and use SvgProxy to
update any element using a CSS selector.
<SvgLoader width="100" height="100" path="/sample1.svg">
<SvgProxy selector="rect" fill="red" />
</SvgLoader>
If you are interested I wrote an article about it sometime ago
https://medium.com/#hugozap/svg-manipulation-tools-for-react-e1d58b754c81
Within an svg tag, there multiple image elements, showing thumbnail images. Because of the large number of images, the page loading tooks a long time. So I want to implement an easy lazy load like David Walsh’s Simple Image Lazy Load and Fade. For img elements it works fine. But for image elements of an SVG area, the load will not be done.
Example:
<div>
<img id="myimg" height="20" width="20" data-src="img1.jpg"/>
</div>
<div>
<svg width="10%">
<image id="myimage" height="20" width="20" xlink:href="img1.jpg"/>
</svg>
</div>
And the JS coding:
// This works fine
var img = jQuery("#myimg");
img.attr('src', img.attr('data-src'));
img.on("load", function () {
img.removeAttr('data-src');
});
// This doens't work, onload will not be processed, image will not be not shown
var image = jQuery("#myimage");
image.attr('xlink:href', image.attr('data-href'));
image.on("load", function () {
image.removeAttr('data-href');
});
The scripting will leave the page in this way:
<div>
<img id="myimg" height="20" width="20" data-src="img1.jpg"/>
</div>
<br>
<div>
<svg width="10%">
<image id="myimage" height="20" width="20" data-href="img1.jpg" xlink:href="img1.jpg"/>
</svg>
</div>
Why is onload not working for this SVG image element?
You have several small mistakes:
<image/> is a self-closing tag,
xlink:href should be used without xlink: prefix,
it's better to set eventListener before you changing attribute.
See the snippet:
var image = jQuery("#myimage");
image.on("load", function () {
console.log('loaded');
image.removeAttr('data-href');
});
image.attr('href', image.attr('data-href'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg>
<image id="myimage" width="150" height="150" data-href="https://pbs.twimg.com/profile_images/843090368837042176/Nl-rCb9c_400x400.jpg"/>
</svg>
Here is my solution to the same problem where I keep using the xlink:href attribute for the raster image to show inside the SVG, but still lazy-load on click. I'm using different lazy-load plugin (jquery.lazy.js) but it's very similar:
<svg>
<image id="lazy-img" class="lazy" width="" height="" data-source="myimage.jpg" />
</svg>
$('.someElement').on('click', function() {
var image = $('#lazy-img");
image.attr('xlink:href', 'myimage.jpg');
image.attr('href', 'myimage.jpg');
});
The idea is that the initial HTML markup is for the lazy-loading images and on click event we are swapping the markup back to work with SVG, after the image is lazy-loaded.
I'm developing a JavaScript class to show all SVG objects, but when I create the element "image", the browser doesn't display it. Though if I copy the generated code and put it in another document, the image is displayed.
When I searched the image using Firebug's inspector, the object appears but the image is not displayed.
I created the object using appendChild(), setAttribute() and setAttributeNS()
This is the generated code:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="100%" width="100%" >
<image width="50" height="50" xlink:href="logo.png" y="20" x="20" id="d"></image>
</svg>
What I am doing wrong?
The problem were the namespaces. This is the correct form to create images dynamically:
image.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'flower.png');
More imformation can be found on MDN's 'Namespaces Crash Course'.
How would I modify an SVG file after it has been loaded by the browser, preferably through jquery? A simple example would be pressing a button and the color of the SVG element changes. Any documentation would help as well.
EDIT: This link helped a great deal:
w3.org/Graphics/SVG/IG/resources/svgprimer.html#SVG_in_HTML
You can't "modify" SVG files (except by changing them on the server). SVG files define a collection of SVG objects, each of which can be identified with an ID, if you wish. These objects can be manipulated with JavaScript like you would any DOM element (e.g. setAttribute, etc). Check http://www.w3.org/TR/SVG11/types.html#BasicDOMInterfaces for the DOM interfaces. Notice that SVGElement extends Element, which is the basic DOM element type.
EDIT: simple example:
<html>
<body>
<input type="button" onclick="doSVGThing()" value="change">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="aRect" x="10" y="10" height="100" width="100"
style="stroke:#ff0000; fill: #9999ff"></rect>
</svg>
<script type="text/javascript">
function doSVGThing() {
var r = document.getElementById('aRect');
r.setAttribute('style', 'stroke: #00ff00; fill: #99ff99');
}
</script>
</body>
</html>
I have an HTML file that looks somehow like this:
<html>
<div id="test"> ... </div>
<object data="pic.svg" [...]></object>
</html>
Inside pic.svg, I have an element, let's say, a circle, and I want to realize something like that:
<circle onClick="doSomething()" [...]>
Now, in the js function doSomething() (i.e. when someone clicks on the circle) I want to change my "test"-div. How to do this?
You can access the parent document (and consequently the elements there) from inside the svg like this:
var divInParentDocument = window.parent.document.getElementById('test');
Here's a (slightly more complex) example showing how to call a function in the parent html document from inside an svg.
If you want the SVG to live in the same DOM as the HTML, best to use an embedded <svg> element. It's pretty well supported.
Something like
<svg id="svgroot" width="600" height="600"
version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript">//<![CDATA[
function doSomething() {
document.getElementById('test').appendChild(...);
}
//]]></script>
<circle onClick="doSomething()" />
</svg>