How do I render and edit SVG data in React? - javascript

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

Related

How replace content (innerSVG?) from string SVG

I can't get the children from the svg fragment pre-entered in the string.
Need return content <g> element from source string;
Example:
has dom:
<svg>
<g class="parent"> <rect ... /> </g>
<svg>
let strNewContent = '<g class="draggable-group" data-id-device="Light-X[room-1549613406671][0]"> <rect height="75" width="184" x="8" y="0" fill="#DDD" rx="6" ry="6" /> </g>'; // created svg string using handlebars.js
// need replace old content in new content
// need extrude `<rect ... /> & etc...` from string and put (innerSVG)
$('.parent').html($(strNewContent).html()) // I understand it won't work. (It's just to understand what I mean.)
d3.select(svgElem).html(d3.select(svgElem).html()); // костыль для обновления svg документа
ps:Thank you for your patience and understanding for my English
need extrude <rect ... /> & etc... from string and put (innerSVG)
I understand that this can be done in 2 ways (as I can see): by a regular expression, cut the content or convert it to a fragment and try to squeeze out the content and add it to a new element as content (helped by #altocumulus). But I really already tried, many times to convert to a fragment and to squeeze out contents, nothing turns out (only now came to the decision, with a regular expression)(now I will experiment).
ps: What's best to correct (title) the issue for everyone to deal with this problem to solve it?

gsap animation - import only one svg or multiple svgs

I would like to do "complex" animation with gsap and svgs.
but I don't know what is the best approach to this.
it is better to create and to import an unique svg with all the elements or maybe it is better 4 different svgs?
I have 4 different characters: a tree, a lamp, a desk and a man.
basically my animation is move the objects on the x, and appearing and to disappearing stuff.
If the elements of the animation are part of one complex animation, you can use one single SVG for this.
To control the DOM of the SVG via CSS and JavaScript you need to add the SVG directly inline into your HTML page. Not embed via img tag or object tag or similar.
<body>
<h1>My SVG Animation</h1>
<svg width="100" height="100" viewBox="0 0 300 100">
<circle class="animation-element-01" cx="50" cy="50" r="40"/>
<rect class="animation-element-01" x="150" y="20" width="150" height="150"/>
<!-- etc -->
</svg>
</body>
Another advantage of this method is, that there is no additional html requests.
Plus the whole animation can be made responsive via the viewBox.

Generated SVG image doesn't display

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'.

Cannot set opacity to element

I am trying to make and interactive svg which would react to some actions with javascript functions.
My SVG looks like this (this is example of one of many svg I am generating, I deleted some irrelevant elements to make the code more readable):
<svg contentScriptType="text/ecmascript" onmouseover="myOpacity(&apos;msg0&apos;, 0.5)"
onclick="svgClick(&apos;Some example text&apos;)"
width="760" xmlns:xlink="http://www.w3.org/1999/xlink" zoomAndPan="magnify"
onmouseout="myOpacity(&apos;msg0&apos;, 1)"
contentStyleType="text/css" height="30" preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg" version="1.0">
<text fill="black" x="10" id="msg0" font-size="10" y="20">Some text</text>
<script xlink:href="script.js" xlink:actuate="onLoad"
xlink:type="simple" xlink:show="other" type="text/ecmascript"
xmlns:xlink="http://www.w3.org/1999/xlink"/>
</svg>
This is my script.js file with onClick and opacity functions:
function svgClick(text) {
alert(text);
}
function myOpacity(element_id, op_value)
{
element = document.getElementById(element_id);
element.setAttribute('opacity', op_value);
}
The problem is that myOpacity function does not work and nothing happens when I hover over my objects (despite the id should correspond to the argument of the function).
However, the onCLick function works perfectly, so the problem is probably with identifying the element by id.
I am quite stuck here, could you take a look in the code and tell me where did I go wrong?
EDIT: this is a followup from this answer: Interactive SVG - how to choose element to react on mouseover action?
That code works there but it somehow does not do anything in the code I posted here. So my question is why? I know I could do this via attributes, but in that case, I do not know how to handle scenario, when I want to set opacity to one element when mouseover action is triggered on another one...
I pasted your code into a jsFiddle (making the JavaScript inline), and it works without problems in Firefox and Chrome:
http://jsfiddle.net/wpZs6/
However, the hover part could be considerably easier with just a CSS hover selector:
<svg width="760" height="30" xmlns="http://www.w3.org/2000/svg" version="1.0">
<style type="text/css">
svg:hover #msg0 {opacity:.5}
</style>
<text fill="black" x="10" id="msg0" font-size="10" y="20">Some text</text>
</svg>
See here: http://jsfiddle.net/L58z6/
try this :
var divtmp = document.getElementById(element_id);
var newStyle = "filter:alpha(opacity=85);-moz-opacity:0.85; opacity: 0.85;";
divtmp.setAttribute("style", newStyle );

Combining SVG, HTML and Javascript

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>

Categories