Javascript - Connect two lines - javascript

In the following picture:
alt text http://rookery9.aviary.com.s3.amazonaws.com/4478500/4478952_3e06_625x625.jpg
I want to connect the boxes in the above with below, Let us call the bottom edge of the top boxes as A and top edge of the below boxes as B
Now, I have two arrays containing the points in the line A and B say
A = [ {Ax1, Ay1},{Ax2, Ay2},.... ] and B = [ {Bx1, By1},{Bx2, By2},.... ]
In real world it can be like A = [ {100, 100},{120, 100},{140, 100},{160, 100}] and B=[ {120, 200},{140, 200},{160, 200},{180, 200},{200, 200},]
Please look at the black dots in the picture above
How can I get the connectiong points as shown in the pictures? Connecting point must be as close to the center of the line as possible.
Here is what I'm trying to get, but below functions draw line between the two matching points from the starting from the left of the both lines, Any suggessions
drawConnection : function(componentOut, componentIn, connectionKey) {
var outDim = $(componentOut).data('dim');
var inDim = $(componentIn).data('dim');
var outPorts = $(componentOut).data('ports');
var inPorts = $(componentIn).data('ports');
var abovePorts = {};
var belowPorts = {};
var i = 0;
if(outDim.bottomLeft.y < inDim.topLeft.y){
// Now proceed only if they can be connect with a single line
if(outDim.bottomLeft.x < inDim.topRight.x && outDim.bottomRight.x>inDim.topLeft.x) {
// Now get a proper connecting point
abovePorts = outPorts.bottom;
belowPorts = inPorts.top;
for(i=0; i<abovePorts.length; i++) {
for(j=0; j<belowPorts.length; j++) {
if(!abovePorts[i].inUse && !belowPorts[j].inUse && (abovePorts[i].x == belowPorts[j].x)){
console.debug("Drawing vertical lines between points ("+abovePorts[i].x+","+abovePorts[i].y+") and ("+abovePorts[i].x+","+belowPorts[j].y+")");
return true;
}
}
}
}
}
return false;
},
-- Update
I'm exactly trying to get something similar to this http://raphaeljs.com/graffle.html, but the connections should be made with straight lines as shown below
alt text http://rookery9.aviary.com.s3.amazonaws.com/4480500/4480527_1e77_625x625.jpg

Have you tried Raphael.js : http://raphaeljs.com/ ?

Another approach is to use the HTML+CSS engine of the browser, instead of using JS.
You can use a table.
One cell row for each box and a 2 cells row for the connector.
You color one of the border for the connector and use margin, float and width styles, to position the boxes.
I've already used this technique to draw org charts a long time ago... when IE6 was considered the best browser!

Another worth looking at is Processing.js if you want a bit more power. I've used Raphael.js before and that was pretty easy to pickup and use. Just be aware that both utilize the Canvas element which to my knowledge isn't supported in all browsers yet.

Related

Photoshop scripting with JSX in for loop to change fill color of each layer

So, I am tinkering with changing fill colors of layers in a PSD file using JSX. I ultimately want to loop all layers, turning off visibility for all but one, edit the fill color of that layer, save as PNG, and then repeat for all layers and all colors in JSON file. I'm starting small as this is my first attempt, but if your solution can help preempt my downfalls with other tasks then it would be greatly appreciated. Here is what I have (alert properly prompts, but line 5 receives error 1302: no such element referencing line 5):
var layerNum = app.activeDocument.layers.length
alert(layerNum);
var i;
for (i=0;i<layerNum;i++){
var currentLayer = app.activeDocument.layers.index(i)
var myColor = new SolidColor();
//var RGB = HEXtoRGB(Y);
myColor.rgb.red = RGB[255];
myColor.rgb.green = RGB[0];
myColor.rgb.blue = RGB[0];
currentLayer.fill.color = myColor;
}
Is this because the collection of layers does not start at 0? Should I start with layers.index(layerNum) and use i-- to move down the collection? Any insight would be helpful. Thanks in advance to this always helpful community.
This var currentLayer = app.activeDocument.layers.index(i)
should be this: var currentLayer = app.activeDocument.layers[i]
Layers collections are pretty much the same as arrays, starting from 0, so you did it right
As KienT points out you need to use square brackets for layers.
Also it's useful to create a variable that's the app.activeDocument, so you don't have to type that out each time. Looping over the layers backwards (or up) is easy - just remember to take 1 off the layers length. You can adjust also make it ignore the background by making the loop start at 1 instead of 0. You can also adjust the layers visibility from true to false (on and off) as you go.
// call the source document
var srcDoc = app.activeDocument;
var layerNum = srcDoc.layers.length;
// alert(layerNum);
for (var i = layerNum -1; i >= 0; i--)
{
var currentLayer = srcDoc.layers[i];
var myColor = new SolidColor;
// Select the layers as you go
srcDoc.activeLayer = srcDoc.artLayers[i];
// switch layer visibility to on
srcDoc.visible = true;
myColor.rgb.red = 255;
myColor.rgb.green = 0;
myColor.rgb.blue = 0;
app.activeDocument.selection.fill(myColor, ColorBlendMode.NORMAL, 100, false);
}

Tooltips for data in javascript using p5.js

I am trying to make tooltips for a data visualization I made using p5.js but I am completely lost. Nothing I tried works. This is my code as is.
var table;
var i;
var j;
var cellValue;
var label;
var test;
function preload() {
matrix = loadTable("dataLayer2matrix.csv","csv")
labels = loadTable("dataLayer2labels.csv","csv")
test = matrix
}
function setup() {
createCanvas(1500,1500)
noStroke()
fill(0,0,255,10)
angleMode(DEGREES)
background(255,255,255)
matrixStartX = 200
matrixStartY = 250
var matrixRows = matrix.getRows()
var matrixSize = matrixRows.length
// Experiment with grid
fill(75, 75, 75, 50)
for (r = 0; r <= matrixSize; r++) {
rect(matrixStartX , matrixStartY + r * 20 - 1 , 20 * matrixSize, 1)
rect(matrixStartX + r * 20 - 1 , matrixStartY, 1, 20 * matrixSize)
}
// Draw matrix
for (var mr = 0; mr < matrixSize; mr++) {
for (var mc = 0; mc < matrixSize; mc++) {
cellValue = matrixRows[mr].getNum(mc)
fill(49,130,189,cellValue*10)
rect(mc * 20 + matrixStartX, mr * 20 + matrixStartY, 19 ,19)
}
}
// Labels - horizontal
fill(75, 75, 75, 255)
labelsRow = labels.getRows()
for (mc = 0; mc < matrixSize; mc++) {
label = labelsRow[0].getString(mc)
text(label, 10, mc*20+matrixStartY + 15)
}
// Labels - vertical
push()
translate(matrixStartX + 15, matrixStartY - 15)
rotate(-90)
for (mc = 0; mc < matrixSize; mc++) {
label = labelsRow[0].getString(mc)
text(label, 0, mc*20)
}
pop()
//Tooltip when clicked
}
/* if(mouseIsPressed){
fill(50);
text(cellValue, 10,10,70,80);
}*/
}
}
It makes this image:
I want it so that when I go over a square I get the data in it. I really can't seem to do it. Thanks.
I think the advice telling you to use bootstrap is missing the fact that you're using p5.js. Bootstrap is more for dealing with html components, not internal Processing sketches.
Instead, you probably want to do this with p5.js code. The best thing you can do is break your problem down into smaller steps:
Step 1: Can you draw a single rectangle?
Instead of trying to add this new functionality to your existing sketch, it might be easier if you start with a simpler example sketch with just a single rectangle.
Step 2: Can you detect when the mouse is inside that rectangle?
If you know where you're drawing the rectangle, you know its coordinates. You also know the coordinates of the mouse from the mouseX and mouseY variables. So to detect whether the mouse is inside the rectangle, you simply have to use if statements that compare the coordinates of the mouse to the coordinates of the rectangle. There are a ton of resources on google for this, and it might help if you draw some examples out on a piece of paper.
Also, don't worry about the tooltip just yet. Just do something simple like change the color of the rectangle when the mouse is inside it.
Step 3: Can you display the information box?
Again, do this in its own sketch first. Maybe create a function that takes a position and the information you want to display as parameters and displays it in a rectangle. Don't worry about making it a tooltip yet. Just get it displaying. Use hard-coded values for the information.
Step 4: Can you combine your small example sketches?
You have code that triggers when the mouse is inside a rectangle. You have code that draws the tooltip. Can you make it so the tooltip is drawn when the mouse is inside the rectangle?
Step 5: Only when all of the above works, then you should start thinking about adding it to your full sketch.
Instead of using an example rectangle, you'll have to use the rectangles you're drawing on the screen. Instead of calling the tooltip function with hard-coded values, use the values you get from the squares.
Take on those pieces one at a time, and make small steps toward your goal. Then if you get stuck, you can post an MCVE of the specific step you're on. Good luck!

Find the object's name via one of its properties

I have an object that holds all white chess pieces and an object that hold all black chess pieces. Now im writing an if statement that checks whether or not the pieces im working with are both the same color.
the code for objects is:
var whiteFgrs = {King:"&#9812", Queen:"&#9813", Fortress:"&#9814", Bishop:"&#9815", Knight:"&#9816", Peasant:"&#9817"};
var blackFgrs = {King:"&#9818", Queen:"&#9819", Fortress:"&#9820", Bishop:"&#9821", Knight:"&#9822", Peasant:"&#9823"};
and the code that stores the value of chosen positions:
var value1=document.getElementById(elemId1).lastChild.nodeValue;
var value2=document.getElementById(element.id).lastChild.nodeValue;
This returns the piece (eg. "&#9817"). How do I check if this code is a part of whiteFgrs or blackFgrs?
Well, you could look it up in the objects like suggested by the others, but there's a much more simple way to figure out whether a piece is black or white:
value < "&#9818" ? "white" : "black";
// or rather, as `nodeValue` gives you the plain text without html entities:
value < "\u265a" ? "white" : "black";
Iterate and check:
var colorValue = "&#9817";
for (var piece in whiteFgrs) {
if (whiteFgs[piece] == colorValue) {
//found it!
}
}
//If not found in white figures, check black figures.
If you need to do this check very often you could also create an index for faster lookup e.g.:
var index = Object.keys(whiteFgrs).reduce(function(idx, name){idx[whiteFgrs[name]]=name;return idx;},{});
index['&#9817']; // === 'Peasant'

Find the element with the largest area (main content area)?

Given a web page, how do you find the largest rectangle on the webpage which is the main content area?
For example, compare the size of sidebar, header, footer, and main content area. Is it possible to find the main content area by simply searching for the largest rectangle out of all the rectangles discovered on a page?
Usually the tallest and widest rectangle is suspected to be the main content area, wondering if there's an algorithm of some sort in Javascript or Python to test this hypothesis out.
So while the question didn't make much sense to me, I couldn't resist the urge to toy around with the concept of recursively scanning a DOM tree to retrieve and sort elements by their sizeĀ :)
Here's a dumb function for doing so (you can paste it in your browser console):
function scanSizes(root) {
return [].reduce.call(root, function(sizes, node) {
var bounds = node.getBoundingClientRect();
sizes.push({tag: node.outerHTML, area: bounds.width * bounds.height});
var children = node.querySelectorAll("*");
if (children.length > 0)
sizes.push.apply(sizes, scanSizes(children));
return sizes;
}, []).sort(function(x, y) {
var a = x.area, b= y.area;
return a > b ? -1 : a < b ? 1 : 0;
});
}
var sizes = scanSizes(document.querySelectorAll("body > *"));
// sizes[0].tag contains the largest html tag (as a string)
// sizes[0].area its area size in pixels (width * height)
Edit: more seriously, you might be interested in this topic and related answers.
Edit: of course performance wise recursion wasn't a really good idea. You can go with something like this to have a more efficient solution:
function scanSizes(root) {
return [].map.call(root, function(node) {
var bounds = node.getBoundingClientRect();
return {tag: node.outerHTML, area: bounds.width * bounds.height};
}).sort(function(x, y) {
var a = x.area, b= y.area;
return a > b ? -1 : a < b ? 1 : 0;
});
}
var sizes = scanSizes(document.querySelectorAll("*"));
I'm adding another answer because I've just stumbled upon the <main> HTML5 element spec, which developers are supposed to use to define their main contents area, so that's probably the very first element you'll want to check for in any scraped page.
So basically you should check for any single <main> or role="main" element in the page, then only use other contents detection strategiesĀ :)
The current answer is overly complex. The main thing you need to know is element.getBoundingClientRect();. Here's a smaller function - I'm looking for the biggest table but you can use any CSS selector you want.
// Fix NodeList.sort()
NodeList.prototype.sort = Array.prototype.sort
var elements = document.querySelectorAll('table')
var getArea = function(element){
var rectangle = element.getBoundingClientRect();
return rectangle.width * rectangle.height;
}
elements.sort(getArea)[0]

Prevent touching corners (JS Game)

How can I prevent this map generator from creating touching corners like this:
-X
X-
Or
X-
-X
Here is a simplified example of the generator: http://jsfiddle.net/fDv9C/2/
Your question answers itself, almost.
Here's the fiddle: http://jsfiddle.net/qBJVY/
if (!!grid[y][x] && !!grid[y+1][x+1] && !grid[y+1][x] && !grid[y][x+1]) {
good=false;
grid[y+1][x]=2;
}
It simply checks for the combinations you do not want and patches them up. It always adds a grid point so as not to disconnect any parts of the map.
This in turn may lead to another situation where the issue may occur, but if it changed anything (that is, if it found a problem), it will simply check again. This can be optimized, for instance by recursively adjusting whatever was changed, but usually it only needs 1 or 2 passes. There's a limiter on there to not allow more than 100 passes, just in case there is some unforeseen circumstance in which it cannot fix it (I can't think of such a situation, though :) ).
Because of the way that you are creating board it's very difficulty to do this checking during generation. I create simple function that check board after. It's using flood algorithm. Here is the fiddle http://jsfiddle.net/jzTEX/8/ (blue background is original map, red background is map after checking)
Basically we create second array grid2. After filling grid we run recursively floodV function
function floodV(x,y) {
var shiftArray = [[0,1],[0,-1],[1,0],[-1,0]];
grid2[y][x]=1;
for(var k=0;k<4;k++) {
var x1=x+shiftArray[k][0];
var y1=y+shiftArray[k][1];
if(grid[y1][x1] == 1 && grid2[y1][x1] == 0 && checkV(x1,y1)) {
grid2[y1][x1] = 1;
floodV(x1,y1);
}
}
}
with the check function
function checkV(x,y) {
var checkVarr = [[-1,-1], [-1,1], [1,1], [1,-1]];
for(var k=0;k<4;k++) {
if(grid[y+checkVarr[k][0]][x+checkVarr[k][1]] == 1 && grid[y+checkVarr[k][0]][x] == 0 && grid[y][x+checkVarr[k][1]] == 0 && grid2[y+checkVarr[k][0]][x+checkVarr[k][1]] == 1)
return false;
}
return true;
}
This isn't perfect because we can sometimes throw away big parts of the map but if we try to start adding new elements we have to check whole map again (in worths case).
This is what I did: http://jsfiddle.net/fDv9C/13/
Where's the magic happening? Scroll down to lines 53 through 58:
var bottom = y_next + 1;
var left = x_next - 1;
var right = x_next + 1;
var top = y_next - 1;
if (grid[top][left] || grid[top][right] ||
grid[bottom][left] || grid[bottom][right]) continue;
In short your touching corner points can only occur at the computed next position. Hence if any one of the four corner neighbors of the next position exists, you must compute another next position.
You may even decrement the counter i when this happens to get as many paths as possible (although it doesn't really make a big difference):
var bottom = y_next + 1;
var left = x_next - 1;
var right = x_next + 1;
var top = y_next - 1;
if (grid[top][left] || grid[top][right] ||
grid[bottom][left] || grid[bottom][right]) {
i--;
continue;
}
See the demo here: http://jsfiddle.net/fDv9C/12/
Edit: I couldn't resist. I had to create an automatic map generator so that I needn't keep clicking run: http://jsfiddle.net/fDv9C/14/

Categories