Clearing Elements in SVG group - javascript

So I have a program that is drawing circles to represent charges, and it can also draw electric field lines and field magnitude lines. However, I want to add in the functionality of being able to erase all of the field lines and leave the charges, or erase all of the elements. Everything that is drawn goes into this svg:
<svg version="1.1" id="svg" x="0px" y="0px"
width="710px" height="510px" viewBox="0 0 710 510" style="enable-background:new 0 0 700 500;" xml:space="preserve" onmouseup="mouseUp(evt)">
<defs>
<marker id="markerArrow" viewBox="0 0 10 10" refX="1" refY="5"
markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</defs>
<g id="gridLineGroup"></g>
<g id="fieldLineGroup"></g>
<g id="chargesGroup"></g>
</svg>
As you can see, there are groups created for each of the different types of drawings. So once I want to clear any one of those three groups, I want it to delete all of the elements in that group but leave it to be filled up again. I don't want the user to have to restart the webpage to redo any mess ups. I've looked around a lot and have been unable to find a solution that works for my program. It is a stock html program.
The latest function I tried to run was a button click that ran this function:
function clearLines() {
document.getElementById("svg").removeChild("fieldLineGroup");
}
Thank you for any help.

I created a fiddle here: https://jsfiddle.net/mattbatman/1vqkgqp4/.
I used remove over the collection instead of removeChild.
I selected all paths within the group, made the selection an array so I could iterate over it with forEach, and called remove on each element:
button.addEventListener('click', () => {
const paths = [].slice.call(document.querySelectorAll('g#gridLineGroup path'));
paths.forEach(path => { path.remove(); });
});

Related

Why is SVG textPath not working in Firefox when rendered by React

I'm trying to render a react component with an inline SVG element that has a text along a path. This is what is returned from the render method:
<div className="textsvg">
<svg width="100%" height="100%" viewBox="-50 -50 100 100">
<defs>
<path id="textPathTop" d={`
M 0 40
A 40,40 0 0 1 0,-40
A 40,40 0 0 1 0,40`}></path>
<path id="textPathBottom" d={`
M 0 -41.8
A 41.8,41.8 0 0 0 0,41.8
A 41.8,41.8 0 0 0 0,-41.8`}></path>
</defs>
<use xlinkHref="#textPathBottom" fill="none" stroke="red"></use>
<text fill="red" fontSize="4.5"><textPath xlinkHref="#textPathBottom">We go up, then we go down, then up again</textPath></text>
</svg>
</div>
This shows the "We go up, then we go down, then up again" text, but just in a straight horizontal line starting from 0,0.
Copying the resulting html into a codepen shows the result as it should look, using the textPath.
Why is the textPath ignored when rendered with ReactJS?
Using React 15.3.1 and checking in FF 52.0.2(32bit)
Already tried using _dangerouslySetInnerHTML for textPath, but that didn't work either.
Check if you have a <base href="..."> tag in your <head> element.
If so, Firefox won't be able to display your text, while Chrome will.
Firefox is searching for your xlink:href attribute at the base href url, it does not find it, so the text is just ignored.
A workaround is to use an absolute url :
<textPath xlink:href="http://pathtoyourpage#textPathBottom">
It is easier if you generate the svg with javascript :
textPath.setAttribute('xlink:href', `${location.href}#textPathBottom`)
Some similar weird behavior happen with mask and filter attributes.

Draw curved lines with css or canvas

I need to draw dynamic curved lines to show flight durations.
Any idea how I can do it?
I was try with clean css but have some rendering problems, I think only method is to use canvas.
You could use SVG it's a bit more browser agnostic I suppose.
SVG Browser Support
Canvas Browser Support
Something like this in your HTML :
<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
</svg>
Of course this could be generated via Javascript and then rendered. JSFiddle
SVG Tutorial
A Brief intro into the dynamic JS generation would be something along these lines. :
Create your dom element :
<svg id="flight" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>
Now we add some JS attributes that you will generated based on variables in flight info:
var svgNS = "http://www.w3.org/2000/svg";
var flightPath = document.createElementNS(svgNS,"path");
flightPath.setAttributeNS(null,"id","path_1");
//This is what you need to generate based on your variables
flightPath.setAttributeNS(null,"d","M10 80 Q 95 10 180 80");
//Now we add our flight path to the view.
document.getElementById("flight").appendChild(flightPath);
Add some CSS Animation to make it a little prettier and you end up with the following example :
JSFiddle Dynamic

SVG childNodes return text

I have an inline SVG and try to loop over all paths within a group element. When using childNodes I found out that Browsers add an extra text child for every path. I am curious why browsers are doing so and if there is a smart way to just loop over real child elements.
I've created a little JSBin to demonstrate the behaviour: http://jsbin.com/tutisakege/1/edit?html,css,js,console,output
(Check the output of the console)
HTML
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 100 100">
<g id="test">
<path d="M50 0 L0 100 L100 100 Z" />
<path class="red" d="M25 0 L25 25 L75 0 L75 25 Z" />
</g>
</svg>
JS
var group = document.querySelector('#test'),
children = group.childNodes;
The childrenobject now holds 5 entries even though my test group only has 2 paths.
Note: I know I could loop over all entries and check whether I have an instance of SVGPathElement but that seems a but cumbersome to me.
(I've tested it in the latest Chrome and Firefox)
Browsers didn't add it, they are right there in the document source. There is whitespace between the path elements i.e. carriage returns and spaces.
You can skip the text by using element.children but that apparently only works on Firefox and Chrome so if you want it done portably you'll probably need to stick with checking for element instances as you suggest in the question.

Manipulating individual tiles in an SVG pattern [duplicate]

I'm trying to create an interactive grid for a web game (HTML, JS, etc.), in which every cell should change it's fill on hover/click. I need both a regular square grid, and a triangular grid. I want it to be vector based so that it will scale nicely to fit different screen sizes. I thought the easiest way would be to create a pattern and fill it on a rectangle. This is the code I have so far:
<pattern id="baseTile" width="10" height="10" patternUnits="userSpaceOnUse">
<path id="tile" d="M 0,0 L 0,10 10,10 10,0 Z" fill="none" stroke="gray" stroke-width="1"/>
</pattern>
For the square, and this for the triangular grid:
<pattern id="baseTile" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M 5,0 L 10,2.5 10,7.5 5,10 0,7.5 0,2.5 Z" fill="none" stroke="gray" stroke-width=".1" />
<path d="M 5,0 L 5,10" fill="none" stroke="gray" stroke-width=".1" />
<path d="M 0,2.5 L 10,7.5" fill="none" stroke="gray" stroke-width=".1" />
<path d="M 0,7.5 L 10,2.5" fill="none" stroke="gray" stroke-width=".1" />
<path d="M 0,0 L 0,2.5 M 0,7.5 L 0,10" fill="none" stroke="gray" stroke-width=".1" />
<path d="M 10,0 L 10,2.5 M 10,7.5 L 10,10" fill="none" stroke="gray" stroke-width=".1" />
</pattern>
They produce the grids I need, but I don't know how to target each cell individually. I'm guessing since I've found no information on this, it's just not possible, and some other solution other than should be used. Any ideas?
Edit:
I want to be able to cycle through different fills on mouse click. For the square grid, I'm using the code I found here: http://bl.ocks.org/bunkat/2605010 but for the triangular lattice, I have absolutely no idea where to begin. That's why I thought of .
PS: I should probably add I have no programming experience, I'm trying to make a nonogram game to teach myself some Javascript.
Patterns are purely decorative. Targetting a single tile within a pattern would be like targetting a single colour within a gradient. Better not to think about them as distinct "tiles", and instead think of it as a sheet of repeating wallpaper.
So what to do? Well, you are going to need a distinct element for each piece that you want to be able to manipulate. But since they are mostly the same, you'll want to use <use> elements to repeat the graphics. You'll need to do a bit of math to figure out how to position the triangles just right, but no worse than what you had to do to figure out that pattern. It will of course be easiest to create the elements with a loop in your JS script, although you could hard code the original elements in a <defs> section.
Moreover, you don't specify what you want to do with the individual cells. If you are going to be changing their appearance, it might help to remember that you can set styles on the <use> element and these will be inherited by the re-used graphics. So if you don't set fill/stroke directly, you can change them by styling the <use>, instead of having a separate, differently coloured template to swap in.

Convert svg box to a css3 rotated div

I used a vector program to draw and rotate a box shape and the exported it as a svg file.
My goal is to read this svg data with javascript and use it to create a matching div. The div should be absolutely positioned and rotated with css3 to match the shape, position and angle of the svg box.
This might be quite a challenge (at least for me) so I'm not sure what would be the best way to approach the task. The svg code looks like this:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="800px" height="600px" viewBox="0 0 800 600" enable-background="new 0 0 800 600" xml:space="preserve">
<rect x="172.5" y="154.5" transform="matrix(0.8779 -0.4788 0.4788 0.8779 -68.2383 143.3385)" fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" width="149" height="102"/>
</svg>
I imagine the rect x and y values can be used directly to define the width and height of the div. But how to determine the correct rotation value for css..
SVG transforms are equivalent to -x-transforms using matrix(). Basically you want to take the SVG matrix and add commas.
So your SVG transform up there is equivalent to:
-webkit-transform: matrix(0.8779 ,-0.4788 ,0.4788 ,0.8779, -68.2383,143.3385);
http://jsfiddle.net/8P76p/
(Incidentally, that's not a pure rotation, it's a rotation + translate.)

Categories

Resources