How do I set the style of SVG CSS attributes in Javascript? - javascript

I'm trying to dynamically determine the length of an array of SVG paths and then insert this value into the HTML DOM style object for the attributes stroke-dasharray and stroke-dashoffset.
var horizontals = document.getElementsByClassName('hLine');
for (var i = 0; i < horizontals.length; i++ ) {
var drawingComponent = horizontals[i],
length = svgPiece.getTotalLength();
horizontals[i].style.strokeDasharray = length;
horizontals[i].style.strokeDashoffset = length;
}
In the example found here, all the .hLine paths (all the horizontal lines) should animate, but they do not.
Is this because strokeDasharray and strokeDashoffset aren't supported?

For a start, there are some things wrong with that Javascript:
var horizontals = document.getElementsByClassName('hLine');
Your SVG doesn't have any elements with the class 'hLine'.
length = svgPiece.getTotalLength();
'svgPiece' is not defined anywhere.
Try something like this:
var horizontals = document.querySelectorAll('#horizontal path')
for (var i = 0; i < horizontals.length; i++ ) {
var path = horizontals[i],
length = path.getTotalLength();
path.style.strokeDasharray = length;
path.style.strokeDashoffset = length;
}
Demo here - although there is still some work to do to get the animation working properly.

You can always also just fix the path length by setting pathLength (https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength) to a value (like 100 for easy percent-based modification).

Related

Joining intersecting paths in illustrator

Short term problem: I have three paths on an artboard. The end of one path has a point at the same position as the beginning of another. The other path is separate. They are all grouped. I have some code that loops through the pathsin the group, and if one path ends where another begins it tried to join them together. The group must be highlighted. To start with my artboard look like this (The top line is two paths):
An after the script is run it looks like this:
With a lot of points added to the end of the line underneath. Could someone lend me a hand with this, Ideally, I'd like it to look like this:
The code looks like this:
var doc = activeDocument;//Gets the active document
var numArtboards = doc.artboards.length;//returns the number of artboards in the document
var intersections = true
var group = doc.selection[0]
var paths = []
var intersecttions = 0
// Builds an array of all the paths in the grouped object
if (group !== undefined && group.pageItems.length >= 2) {
for (var i = 0; i < group.pageItems.length; i++) {
var item = group.pageItems[i];
if (item instanceof PathItem) {
item.id = 'Path No' + i;
paths.push(item)
}
}
}
//Sets the first path that will be added to
$.write('paths length ', paths.length,'\n')
var chain = paths[0]
var chainPoints = chain.pathPoints
var chainLength = chainPoints.length - 1
var c1 = chainPoints[0]
var c2 = chainPoints[chainLength]
$.write('c ', c1.anchor,':::', c2.anchor,'\n')
//loops through the paths in the group to see if any overlap the first past
for (var i = 1; i < paths.length-1; i++) {
var link = paths[i]
$.write(link, '\n')
var linkPoints = link.pathPoints
var linkLength = linkPoints.length - 1
$.write('l ', l1.anchor, ':::', l2.anchor, '\n')
if (toString(c1.anchor) === toString(l2.anchor)) {
$.write('inttersection', '\n')
$.write('link', link.id, '\n')
for (var j = 0; j < linkLength; ++j) {
chain.pathPoints.add(linkPoints[j])
$.write (linkPoints[j], '\n')
}
}
}
The first problem is that it's not detecting the instance of overlap correctly. The line:
if (toString(c1.anchor) === toString(l2.anchor)) {
is not comparing one string to another but comparing a true response with another true response. It should be:
if (String(c1.anchor) === String(l2.anchor)) {
you also have to pass across the attributes of each point you are adding to the line and remove the old line, so within the j loop you'll need to add the following
for (var j = 0; j < linkLength; ++j) {
var pp1 = chainPoints.add()
var p2i = linkPoints[j];
pp1.anchor = p2i.anchor;
pp1.rightDirection = p2i.rightDirection;
pp1.leftDirection = p2i.leftDirection;
pp1.pointType = p2i.pointType;
pp1.handle = p2i.handle;
}
link.remove();
This seems to work except that it doesn't add the last point of the second line. I'm guessing that the loop length may not be set correctly If I work it out I'll update the post. I found this in Hiroyuki Sato code for his JoinReasonable scripts http://shspage.com/aijs/en/

adjusting linked indexes for reorganized arrays

I have a table that can be dynamically styled with various colors and a palette of colors that serves as a reference to those colors. When the user has finished coloring, I want to compile the file to JSON. I can fetch the necessary values likewise:
// note _colors is a global variable declared elsewhere
var $rowSelect = $("#rowSelect");
var $colSelect = $("#colSelect");
var $colorBoard = $("#colorBoard");
var $upload = $("#upload");
$upload.on("click", function() {
var numRows = Number($rowSelect.val());
var numCols = Number($colSelect.val());
var pixels = [];
var colors = [];
var comp_colors = [];
var $rows = $colorBoard.children();
for(var i = 0; i < numRows; i++) {
var $cols = $rows.eq(i).children();
for(var ii = 0; ii < numCols; ii++) {
$cell = $cols.eq(ii);
pixels.push(Number($cell.attr("data-colorid")));
}
}
var usedColors = pixels.filter((v, i, a) => a.indexOf(v) === i);
for(var i = 0; i < _colors.length; i++) {
colors.push(_colors[i] ? _colors[i].color.getColor() : null);
if(_colors[i] && usedColors.includes(i) && !comp_colors.includes(colors[i])) comp_colors.push(_colors[i].color.getColor());
}
}
Since colors can be deleted, duplicated, or unused in my UI, I cleaned up my raw color array colors into the comp_colors array. For example, an array of unprocessed colors may look like: [null, "#EF1A1A", null, "#40E255", "#0B1DE3", "#FFFFFF", "#FFFFFF"]. If "#0B1DE3" was not actually present in our pixel array, the cleaned up version would look like: ["#EF1A1A", "#40E255", "#FFFFFF"].
The problem is that cleaning up the color array has offset the indexes that the values of the pixels array were using to reference the colors. For example, using the color situation above, a fetched array of pixels may look like this: [1,3,3,1,5,6,5,1,3,6], but the revised version for the cleaned up color set would be: [0,1,1,0,2,2,2,0,1,0].
What is the most efficient way to correct these values to the appropriate indexes?
I found a concise method, but I don't feel like it is very efficient. I have to iterate through every pixel to achieve this, which can be costly at with large creations. The new list of pixels will be loaded into comp_pixels:
for(var i = 0; i < cells.length; i++) comp_pixels.push(comp_colors.indexOf(colors[pixels[i]]));

How to characterize z-indexing for the DOM? (2)

I've been a bit care-less with choosing z-indexes in my CSS.
I'd like to traverse the DOM and report all the z-indexes with their respective ID's.
For example:
id z-index
header 10
main 0
menu 20
The end result would be an object whose keys are the element id and the value is the z-index. One might call it z_obj
// pseudo code
var z_obj = {el_id: el_zindex};
Getting the z-index for each element ( el ) should be easy using something like filter and the code below:
// attr is attribute
data = _.filter(el.attributes, function (attr) {
return (/^z-index/).test(atttr.name);
});
But how would I traverse the DOM to get all z-indexes and store that in an object?
I'd like to do this w/ out libraries, and using the code above if possible.
This would be a good debug tool in general.
You can get all elements with getElementsByTagName("*"), iterate over the collection with a for loop, and use window.getComputedStyle(Node). From there, you can retrieve the z-index. Here's an example:
var zObj, allEls, i, j, cur, style, zIndex;
zObj = {};
allEls = document.body.getElementsByTagName("*");
for (i = 0, j = allEls.length; i < j; i++) {
cur = allEls[i];
style = getComputedStyle(cur);
zIndex = style.getPropertyValue("z-index");
zObj[cur.id] = zIndex;
}
DEMO: http://jsfiddle.net/mj3cR/1/
Where zObj is an Object, keys represented by the id attributes, and values represented by the z-index style.
Note that getComputedStyle is not supported in IE < 9, but of course there are many polyfills :)
reportZ = function () {
var z_arr = {},
all_el = document.body.getElementsByTagName("*"),
i,
len,
cur,
style,
z_index;
for (i = 0, len = all_el.length; i < len; i++) {
cur = all_el[i];
style = win.getComputedStyle(cur);
z_index = style.getPropertyValue("z-index");
if (z_index !== "auto") {
z_arr[i] = [cur.id, cur.tagName, cur.className, z_index];
}
}
return z_arr;
};

Can't perform more than one operation on an ImageData object?

I am trying to use canvas to mask an image using a few separate masks (I managed to put every one of them in a separate ImageData object).
The mask images are black and white, no alpha channel. I need to layer masks on top of each other, so I need to (un?)premultiply the alpha, or put the red channel in the alpha channel.
It works beautifully when I try to apply only one mask to the original image, but it breaks when I try using more than one. I'm doing it like this:
base.iMask = function(cx, imgData, maskLeft, maskRight, maskTop, maskBottom) {
var index = 0;
var newdata = cx.createImageData(imgData);
for (var i=0; i<maskLeft.width; i++) {
for (var j=0; j<maskLeft.height; j++) {
index = (i*4)*maskLeft.width+(j*4);
newdata.data[index+3] = maskLeft.data[index];
}
}
// The same cycle is repeated for each mask (4 total)
return newdata;
The problem is that only the last mask gets applied. I tried to use putImageData and then getImageData before each cycle, but it won't work!
A function that performs a (un)premultiply on an ImageData() object would solve my problem. Any ideas?
Fixed it, but I'll answer it anyway for the people that might be interested.
The problem was that I was overwriting the pixel data. That's the new code:
var index = 0;
for (var i = 0; i < maskData.width; i++) {
for (var j = 0; j < maskData.height; j++) {
index = (i * 4) * maskData.width + (j * 4);
maskData.data[index] = 255 - (255 * 4 - stripeTopData.data[index] - stripeBottomData.data[index] - stripeLeftData.data[index] - stripeRightData.data[index]);
}
}
This combines all four masks and generates a B&W image that I can use later to mask my original image.

How to create array and divs with a unique height using jQuery?

I need 100 small divs for my chart, every time I generate them, I they all appear as the same height; the last value from the array.
var valuesG = new Array(100);
for (i = 0; i < valuesG.length; i++ ) {
valuesG[i] = Math.floor(Math.random() * 101);
$("#second").append("<div class='single'></div>");
$(".single").css('height', valuesG[i])
}
Any ideas why this is happening?
You are applying the new height to ALL the .single elements in every iteration. In the last iteration, they end up having the same height.
You could do it like this:
$('<div class="single">')
.css('height', valuesG[i])
.appendTo($('#second'));
Also, your code is not very efficient, take a look at this:
var valuesG = [], //array literal
$elements = $(); //empty jQuery object
for (var i = 0; i < 100; i++) { //we don't have to query array length each iteration
valuesG[i] = Math.floor(Math.random()*101);
//collect the elements into a jQuery object
$elements = $elements.add($('<div class="single">').css('height', valuesG[i]));
}
$elements.appendTo($("#second")); //insert to DOM once - much quicker
jsFiddle Demo
Currently, you're selecting all elements with class single. To get the desired effect, use the appendTo method in the way as shown below.
Side note, the generated heights are not unique, but random. It's possible that two elements exist with, say, height 50. See this question for a method to generate unique random numbers.
var valuesG = new Array(100), i;
for ( i=0; i < valuesG.length; i++ )
{
valuesG[i] = Math.floor(Math.random()*101);
$("<div class='single'></div>")
.css( 'height', valuesG[i] )
.appendTo("#second");
}
You get only one height(last one) because you set same css class in all div and update it's height in every loop so last height value will be applied to all.
As a solution try this:
for ( i=0; i < valuesG.length; i++ ) {
valuesG[i] = Math.floor(Math.random()*101);
$("<div class='single'></div>").css('height',valuesG[i]).appendTo("#second");
}

Categories