Manipulating individual tiles in an SVG pattern [duplicate] - javascript

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.

Related

jQuery: select one specific element from clicked SVG group

So, I have a simple SVG group:
<g id="interceptor">
<ellipse cx="0" cy="15" rx="6" ry="14" fill="url(#gradient)"/>
<polygon points="0,-20 7,10 0,0 -7,10" fill="blue"/>
<polygon points="0,-20 7,10 0,0" fill="darkblue"/>
</g>
Which I then use like this:
<g class="ship" id="ship3" transform="rotate(-180,480,24) translate(480,24)">
<use xlink:href="#interceptor"/>
</g>
Now, what I would like to do is to add a stroke around the first polygon from the group when the whole group is clicked, but I don't know how to access contents of the interceptor group via jQuery. I was thinking about something like this, but contents() returns nothing:
$(".ship").click(function() {
$(this).find("use").contents().find("polygon").first().attr({"stroke-width":1, stroke:"white"});
});
I can, of course, add a stroke around the entire ".ship" and it works, but it's not what I want because this creates strokes between polygons in the group. Additionally, there can be a number of separate objects that use the #interceptor group, and only the one that is actually clicked should get the stroke. Is that doable?

How can I create a PATH between two elements without specifying its coordinates in SVG

Imagine I have a javascript library that is arbitrarily manipulating the position of two elements. I want to draw a spline (path) that starts at one element and ends on the other one, like:
<circle cx="50" cy="50" r="5" />
<circle cx="100" cy="50" r="5" />
<path d="M 369 320 C 426 320 386 304 444 304"/>
Now, I thought about transforming the origin of the path to match the center of the circle, but that would mean "hardcoding" the coordinates. If I want to move the circle, I would have to recalculate the path data.
So, question (1) how can I do something like that without resorting to javascript? and (2) iff javascript is the sole solution for this problem, then which technique (including libraries) would you recommend that would ease the task of allowing the reference objects to be arbitrarily moved and automate the necessary path recalculations?

display all elements in svg in a fixed area

I have some javascript code that dynamically creates SVG polygons at various locations. Currently if a polygon is created outside of the range of the SVG element's width and height, then it isn't displayed. I would like the polygons to scale down so that each polygon is visible, within the specified area.
As an example this only displays one triangle:
<svg width="100" height="100">
<polygon points="0,0 0,100 100,50 " fill="blue"></polygon>
<polygon points="100,0 100,100 200,50 " fill="blue"></polygon>
</svg>
but I would like it to display something closer to what this displays (two triangles scaled to fit inside a 100 by 100 box,) without having to change the points myself:
<svg width="100" height="100">
<polygon points="0,0 0,100 50,50 " fill="blue"></polygon>
<polygon points="50,0 50,100 100,50 " fill="blue"></polygon>
</svg>
This seems like it should be easy to do but I searched for "svg scale to fit" and "display all elements in svg in a fixed area" but I couldn't find anything related to my problem

Count all hex colour codes in SVG/string

I have an SVG image and I want to get all the colour hex codes in an array.
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g display="inline">
<title>Layer 1</title>
<ellipse ry="116" rx="66" id="svg_1" cy="130.7" cx="375.2" stroke-width="3" stroke="#000000" fill="#FF0000"/>
<ellipse ry="104" rx="68" id="svg_2" cy="133.7" cx="248.2" stroke-width="3" stroke="#000000" fill="#FF0000"/>
<ellipse ry="73" rx="47" id="svg_3" cy="161.7" cx="231.2" stroke-width="3" stroke="#000000" fill="#FF0000"/>
<rect id="svg_4" height="77" width="83" y="66.7" x="225.2" stroke-width="3" stroke="#000000" fill="#0000ff"/>
</g>
</svg>
So in this case I have 3 different colours. Yet in total I have 8 as there are recurrences.
I can count all with.
function count_colours(data){
return data.match(/#/g).length;
}
And obviously I get eight plus any other occurrence of #.
The issue I have is anything I can think of is too heavy. I need a light simple solution if there is one. Is there a simple way to achieve this? Getting all the hex codes in an array with no duplicates would be amazing.
EDIT:
OK, so iterate through the array and check the hex code is valid using..
var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test('#XXXXX')
Then remove duplicates using
_.uniq(hex_codes);
But how would I build the initial array, that's the part I am struggling with. Would I use indexOf() in the initial iteration. This all seems very messy.
How about this?
function count_colours(data) {
var n = 0, matches, cols = {};
if (matches = data.match(/\#[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?/g)) {
for (var i=0; i<matches.length; i++) {
if (!cols[matches[i]]) {
cols[matches[i]] = 1
n++;
}
}
}
return n;
}
Demo here
You may also need to take account of the fact that "#00F", "#00f" and "#0000FF" are all the same colour but will be counted separately. I have assumed here that these files are produced by an editor or something similar which will be consistent in how it lists colours.
Yes there is, depends on your constraints.
I'd go for underscore utility function uniq, as it's not worth writing your own implementation.
http://underscorejs.org/#uniq
There is also another answer in relation to your question here:
Removing duplicate objects with Underscore for Javascript

How would I move an SVG pattern with an element [duplicate]

This question already has answers here:
How to make SVG image pattern fill move with object?
(4 answers)
Closed 1 year ago.
I created the svg pattern seen here:
<pattern id="t" height="20" width="20" patternUnits="userSpaceOnUse" overflow="visible">
<ellipse cx="0" cy="0" rx="20" ry="20" fill="white"/>
<ellipse cx="5" cy="5" rx="15" ry="15" fill="yellow"/>
<ellipse cx="10" cy="10" rx="10" ry="10" fill="blue"/>
<ellipse cx="15" cy="15" rx="5" ry="5" fill="red"/>
</pattern>
Then in my script I created an ellipse that uses the pattern. The problem is, when I move the ellipse around, the pattern stays still behind it instead of moving with the ellipse.
How do I configure the pattern to stay with the element?
You need to use patternContentUnits="objectBoundingBox" click on the rectangle in this example to see: http://jsfiddle.net/longsonr/x8nkz/
Change the patternContentUnits to "objectBoundingBox" (vs. userSpaceOnUse).
More: patternUnits should have no effect on how the pattern is laid out, only its dimensions (userspace units vs. boundingbox units). patternContentUnits is the attribute that you want to set to "objectBoundingBox" - note that that this will then scale your pattern if you change the size of the bounding box. If you don't want this to happen, then you need to use a viewbox attribute on your pattern - which is probably the right way to get the result you're probably looking for (fixed size pattern, positioned relative to its bounding box)
(Also please note that setting overflow to visible results in "undefined" rendering according to the spec aka - not something that you want to do)

Categories

Resources