Values of a graph - javascript

I have a pentagon graph made up with SVG coding. So I made the pentagon with codes like so:
<svg><path cs="100,100" d="M0.5,-62.5 L60.5,-18.5 L37.5,51.5 L-36.5,51.5 L-59.5,-18.5 L0.5,-62.5 M0,0 L0,0"></svg>
Right now, on a graph perspective, the pentagon is showing values of 30 for each side. I am trying to find a way to change the values without always having to go inside PATH CS to change the degree values.
Anyone have an idea, I have been looking it up and found that connecting it with a javascript would be the best case but I have no idea how to write the proper javascript. Could anyone help?

I'm not sure it answers your question. I don't understand what is cs property neither what you really want to modify.
But, here is a way (maybe not the best) to access all your polygon's points by javascript :
You can set all your d points into an array of array, then access each point by modifying it
var p = document.querySelector('path');
var a = [
[ ["M"],[0.5, -62.5] ],
[ ["L"],[60.5, -18.5] ],
[ ["L"],[37.5, 51.5] ],
[ ["L"],[-36.5, 51.5] ],
[ ["L"],[-59.5, -18.5] ],
[ ["L"],[0.5, -62.5] ],
[ ["M"],[0, 0] ],
[ ["L"],[0, 0] ]
];
function draw() {
//loop through the array to join path descriptions with their values
var d = function(){var r = '';for (var i = 0; i < a.length; i++) r += a[i].join('') + " "; return r;};
p.setAttribute('d', d());
}
//EXAMPLes
//Change each value manually then redraw
p.addEventListener('click', function() {
a[1][1][0] ++;
a[2][1][1] --;
draw();
}, false);
//a simple function to change values of set points
function move(point, xy, newValue) {
a[point][1][xy] = newValue;
draw();
}
window.onclick = function() {
move(2, 0, 75);
};
<svg>
<path cs="100,100" d="M0.5,-62.5 L60.5,-18.5 L37.5,51.5 L-36.5,51.5 L-59.5,-18.5 L0.5,-62.5 M0,0 L0,0">
</svg>
If you won't change the structure (number of points) of your polygon, then you can use a simpler structure :
var p = document.querySelector('path');
var a = [
[0.5, -62.5],
[60.5, -18.5],
[37.5, 51.5],
[-36.5, 51.5],
[-59.5, -18.5],
[0.5, -62.5],
[0, 0],
[0, 0]
];
function draw() {
//HardWrite the path descriptions
p.setAttribute('d', "M" + a[0] + " " + "L" + a[1] + " " + "L" + a[2] + " " + "L" + a[3] + " " + "L" + a[4] + " " + "L" + a[5] + " " + "M" + a[6] + " " + "L" + a[7]);
}
//Change each value manually then redraw
p.addEventListener('click', function() {
a[1][0] ++;
draw();
}, false);
//a simple function to change values of set points
function move(point, xy, newValue) {
a[point][xy] = newValue;
draw();
}
window.onclick = function(){ move(2, 0, 75);};
<svg>
<path cs="100,100" d="M0.5,-62.5 L60.5,-18.5 L37.5,51.5 L-36.5,51.5 L-59.5,-18.5 L0.5,-62.5 M0,0 L0,0">
</svg>

Related

Get the color of one pixel at Photoshop scripts

I am trying to figure out how to get the color of one defined Pixel.
In my imagination its shoud look like:
color = get.color.Pixel(x,y);
Maybe someone can help me with this piece of code?
Photoshop's JavaScript API doesn't provide a mechanism like you imagine in your question.
You'll need to utilize the Document.colorSamplers.add([x, y]) method, then read each component color value via its properties:
The following gist shows how to obtain either rgb or cmyk values for a given x,y coordinate:
#target photoshop
// Define the x and y coordinates for the pixel to sample.
var x = 1;
var y = 1;
// Add a Color Sampler at a given x and y coordinate in the image.
var pointSample = app.activeDocument.colorSamplers.add([(x - 1),(y - 1)]);
// Obtain array of RGB values.
var rgb = [
pointSample.color.rgb.red,
pointSample.color.rgb.green,
pointSample.color.rgb.blue
];
// Obtain array of rounded CMYK values.
var cmyk = [
Math.round(pointSample.color.cmyk.cyan),
Math.round(pointSample.color.cmyk.magenta),
Math.round(pointSample.color.cmyk.yellow),
Math.round(pointSample.color.cmyk.black)
];
// Remove the Color Sampler.
pointSample.remove();
// Display the complete RGB values and each component color.
alert('RGB: ' + rgb)
alert('red: ' + rgb[0])
alert('green: ' + rgb[1])
alert('blue: ' + rgb[2])
// Display the complete CMYK values and each component color.
alert('CMYK: ' + cmyk)
alert('cyan: ' + cmyk[0])
alert('magenta: ' + cmyk[1])
alert('yellow: ' + cmyk[2])
alert('black: ' + cmyk[3])
Here's a simple script using a ColorSampler. It's set up to return RGB values.
function PixelSampler(doc) {
this.doc = doc
this.doc.colorSamplers.removeAll();
this.sampler = this.doc.colorSamplers.add([0, 0]);
}
// Return an array of R, G, B pixel values for a particular coordinate.
PixelSampler.prototype.get = function (x, y) {
this.sampler.move([x, y]);
const R = this.sampler.color.rgb.red;
const G = this.sampler.color.rgb.green;
const B = this.sampler.color.rgb.blue;
return [R, G, B];
}
////////////////////////////////////////////////////////
/// SOME TESTS /////////////////////////////////////////
////////////////////////////////////////////////////////
const p = new PixelSampler(app.activeDocument);
alert("Pixel 0 =\n\n" + p.get(0, 0));
$.hiresTimer;
var n = 1000; //p.width * p.height;
for (var i = 0; i < n; i++) p.get(i, 0);
sec = ($.hiresTimer / 1000 / 1000);
alert("Got " + (n / 1000) + " kilopixels in " + sec.toFixed(2) + " seconds.");
This gives me pixel values at about 100 pixels per second on my machine.
I found this and cleaned up the script a bit. Basically, the idea is to:
Save the current image as a raw bitmap.
Read it back in, but on the javascript side.
Do all access to pixels on the javascript side.
This gives me pixel values at about 72,000 pixels per second, not including the overhead of writing the raw data to disk and reading it back in. It has the added benefit that you can set pixel values, too.
// Adapted from https://community.adobe.com/t5/photoshop/get-index-of-each-pixel/td-p/10022899?page=1
// The purpose is to query (and change) pixel values quickly.
//
// The secret to speed is doing everything on the script side rather than ask Photoshop to do things.
// We use files on disk as an intermediary; on the script side, we read / write it as a binary file; on the
// Photoshop side, we save / open it as a raw bitmap.
//
// Only works on RGB 8bpp images, but this could be easily extended to support others.
function RawPixels(doc) {
this.doc = doc;
const currentActiveDoc = app.activeDocument;
// Obtain the width and height in pixels of the desired document.
const currentRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
app.activeDocument = doc;
this.width = Number(doc.width.value);
this.height = Number(doc.height.value);
this.length = this.width * this.height;
this.pixelData = "";
// Return the ruler to its previous state.
app.preferences.rulerUnits = currentRulerUnits;
try {
// We're going to save this document as a raw bitmap to be able to read back in the pixel values
// themselves.
const file = new File(Folder.temp.fsName + "/" + Math.random().toString().substr(2) + ".raw");
// Set up the save action.
// See https://helpx.adobe.com/photoshop/using/file-formats.html#photoshop_raw_format for some info,
// and more technical at https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
var rawFormat = new ActionDescriptor();
rawFormat.putString(stringIDToTypeID("fileCreator"), "8BIM");
rawFormat.putBoolean(stringIDToTypeID("channelsInterleaved"), true);
var saveAction = new ActionDescriptor();
saveAction.putObject(stringIDToTypeID("as"), stringIDToTypeID("rawFormat"), rawFormat);
saveAction.putPath(stringIDToTypeID("in"), file);
saveAction.putBoolean(stringIDToTypeID("copy"), false);
executeAction(stringIDToTypeID("save"), saveAction, DialogModes.NO);
// File is saved; now read it back in as raw bytes.
file.open("r");
file.encoding = "BINARY";
this.pixelData = file.read();
const err = file.error;
file.close();
file.remove();
file = null;
if (err) alert(err);
}
catch (e) { alert(e); }
// Return focus to whatever the user had.
app.activeDocument = currentActiveDoc;
}
// Calculate offset from x, y coordinates. Does not check for valid bounds.
getOffset = function(x, y) {
if (y == undefined) {
// allow linear indices too
y = Math.floor(x / this.width);
x = x - y * this.width;
}
return (y * this.width + x) * 3;
}
// Return an array of R, G, B pixel values for a particular coordinate.
RawPixels.prototype.get = function (x, y) {
const off = getOffset(x, y);
const R = this.pixelData.charCodeAt(off + 0);
const G = this.pixelData.charCodeAt(off + 1);
const B = this.pixelData.charCodeAt(off + 2);
return [R, G, B];
}
// Set the pixel at x, y to the values in RGB.
RawPixels.prototype.set = function (RGB, x, y) {
const off = getOffset(x, y);
// note: note checking that length of p = 3!
const R = String.fromCharCode(RGB[0]);
const G = String.fromCharCode(RGB[1]);
const B = String.fromCharCode(RGB[2]);
this.pixelData = this.pixelData.substr(0, off) + R + G + B + this.pixelData.substr(off + 3);
}
// If any changes were made to the pixels, we need to save them to disk and have Photoshop read that file back in.
// We do that by creating a new layer in the desired document.
RawPixels.prototype.create_layer = function () {
try {
const file = new File(Folder.temp.fsName + "/" + Math.random().toString().substr(2) + ".raw");
file.open("w");
file.encoding = "BINARY";
file.write(this.pixelData);
const err = file.error;
file.close();
if (err) { file.remove(); alert(err); return; }
var rawFormat = new ActionDescriptor();
rawFormat.putInteger(stringIDToTypeID("width"), this.width);
rawFormat.putInteger(stringIDToTypeID("height"), this.height);
rawFormat.putInteger(stringIDToTypeID("channels"), 3);
rawFormat.putBoolean(stringIDToTypeID("channelsInterleaved"), true);
rawFormat.putInteger(stringIDToTypeID("depth"), 8);
var openAction = new ActionDescriptor();
openAction.putPath(stringIDToTypeID("null"), file);
openAction.putObject(stringIDToTypeID("as"), stringIDToTypeID("rawFormat"), rawFormat);
executeAction(stringIDToTypeID("open"), openAction, DialogModes.NO);
file.remove();
// The new active document is the file we just opened. Duplicate its contents into
// a new layer in our desired document, then close this temporary file.
app.activeDocument.activeLayer.duplicate(this.doc.layers[0], ElementPlacement.PLACEBEFORE);
const tempDoc = app.activeDocument;
app.activeDocument = this.doc;
this.doc.layers[0].name = "Pixels";
app.activeDocument = tempDoc;
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
app.activeDocument = this.doc;
}
catch (e) { alert(e); }
}
////////////////////////////////////////////////////////
/// SOME TESTS /////////////////////////////////////////
////////////////////////////////////////////////////////
$.hiresTimer;
const p = new RawPixels(app.activeDocument);
var sec = ($.hiresTimer / 1000 / 1000);
alert("Init RawPixels in " + sec.toFixed(2) + " seconds");
alert("Pixel 0 =\n\n" + p.get(0));
var a = new Array();
for (var i = 0; i < 100; i++) a.push(p.get(i));
alert("Pixel 0-99 = \n\n" + a.toSource());
p.set(0, [1, 200, 3]);
alert("New Pixel 0=\n\n" + p.get(0));
$.hiresTimer;
var n = p.width * p.height;
for (var i = 0; i < n; i++) p.get(i);
sec = ($.hiresTimer / 1000 / 1000);
alert("Got " + (n / 1000 / 1000) + " megapixels in " + sec.toFixed(2) + " seconds.");
$.hiresTimer;
n = 10;
for (var i = 0; i < n; i++) p.set([255, i * 20, i * 10], 1 + i * 2);
sec = ($.hiresTimer / 1000 / 1000);
//alert("Set " + n + " pixels in " + sec.toFixed(2) + " seconds");
p.create_layer();
alert("New layer created with new pixels");

Negation the functionality of the function

I im quite confused in the negation of the functionality of my function. The original function takes 9 elements starting at nth index and decrease their transform position.
function pushIt(max, target, index, count) {
if (count == max || count == img.children ) {
running = false;
return;
}
var tmp = target[index];
var matrix = window.getComputedStyle(tmp).getPropertyValue("transform");
var translate_left = matrix.split(",")[4];
var translate_top = matrix.split(",")[5].split(")")[0]-215;
tmp.style.transform = "translate3d(" + translate_left + "px," + translate_top + "px,0)";
setTimeout(function(){
pushIt( max, target, index + 1, count + 1 );
},50)
}
What i wanted to do is to negate its functionality , e.g it wont decrease but increase transform position of (nth * 3) - 1 element ( counting down 9 elements )
function pushItDOWN(max, target, index , count) {
if ( count == max || index < 0 ) {
running = false;
return;
}
console.log("down");
var tmp = target[index];
var matrix = window.getComputedStyle(tmp).getPropertyValue("transform");
var translate_left = matrix.split(",")[4];
var translate_top = matrix.split(",")[5].split(")")[0]+215;
tmp.style.transform = "translate3d(" + translate_left + "px," + translate_top + "px,0)";
setTimeout(function(){
pushItDOWN(max, target, index - 1, count + 1 );
},50)
}
}
What second function does is takes elements and set their transform to oblivion (e.g out of viewport) and somehow break the functionality of first function.
Did i overlook some key fact that is causing the problem , i seem to fail to find the root of the problem.
Live demo for better understanding
I'm not 100% sure, but most likely this is your error:
This will result in a string:
matrix.split(",")[5].split(")")[0]
Lets say it is "500", then
matrix.split(",")[5].split(")")[0] + 215
// equals
"500" + 215
// results in (because + is both used as string concatenation as addition)
"500215"
// - will work, because it only has one meaning
"500" - 215 // results in 285
Parse the value as an int (or float if necessary) before adding the 215:
parseInt(matrix.split(",")[5].split(")")[0]) + 215

How to prevent a new object of robots from going to the same location as previous robots?

Things you need to know about my Program
I have created a program in JavaScript that executes Robot instruction that you give. per Robot Object.
The robot is inside a rectangle shaped area. It moves with (x,y) points. Such that (0 <= x <= 50) and (0 <= y <= 50)
The instructions are in Strings of continuous of three repeated letters - There are Three letter that represent the movement of the robot
The program runs each letter and moves the robot according to the letter.
If the program finds out the the robot is out of the surface. Then the robot is lost and the coordinates of that particular robot is kept in array of lists called Lost_Robot
My Question:
I don't know how to prevent a new robot from going to the same coordinates that a previous robot got lost (because of out of Rectangle surface).
How can I achieve from preventing another new robot (when I say new Robot, I mean new Robot Object) from jumping to the same location that a previous robot went and got lost.
I have an array of (x,y) of robots that got lost. But how can I use this array from letting a new robot going to this point?
I tried to use for loop that runs the array to see the coordinates, but doesn't do anything.
Also
While your working on my problem, can you also give me few hints on how can I simplify my code yet doing the same functionality, but more efficiently.
=
var orientation = ["N", "E", "S", "W"];
var instruction = ["L", "R", "F"];
var lost_Robot_Scent = [];
// function created for assigning coordinates and an orientation
function Robot_Coordinatation(x, y, orientation) {
// coordinate (x,y) must be located at (0,0) at the initial state of the program
this.x = 0;
this.y = 0;
// orientation assigned
this.orientation = orientation;
// this is printed for the purpose of tidiness
document.write("============================" + "<br />");
// | ( x,y) | e.g(S)
document.write("| ( " + x + ", " + y + " ) | " + orientation + "<br />");
// We have a nested function here that will determine the movement/instruction of the robot
this.Robot_Instruction = function(instruct_The_Robot) {
// We are making sure here that the length of the instruction is less than 100
if (instruct_The_Robot.length <= 100) {
// if...statement - if x & y is bigger than or equal to 0 and smaller than or equal to 50 -> If its true then go inside the if statment.
// Essentiallly, what this statement is actually doing is that its creating the rectangular grid.
if ((x <= 50 && x >= 0) && (y <= 50 && y >= 0)) {
// itterate the array of the instruct_The_Robot
for (var i = 0; i < instruct_The_Robot.length; i++) {
// if any value of instruct_The_Robot is strictly equal to "L", then go inside this if statement. refer to line: 10
if (instruct_The_Robot[i] === instruction[0]) {
// variable Left declared and instantiated with -90°
var Left = -90 + "&#176";
// variable result instantiated with value (x,y) & orientation
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Left + "<br />";
// however, if the if...statment at line: 33 is not true, then follow this : if the value of instruct_The_Robot is equal to "R"...
} else if (instruct_The_Robot[i] === instruction[1]) {
// variable Right instantiated with 90°
var Right = 90 + "&#176";
// variable result instantiated
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Right + "<br />";
// however, if the if...statment at line: 33 & elseif at line: 39 is not true, then if instruct_The_Robot is equal to "F"...
} else if (instruct_The_Robot[i] === instruction[2]) {
// variable y_Plus_One is instantiated with the current value of y and moves y one point forward
var y_Plus_One = y += 1;
// if the negation of x & y_Plus_One is smaller than 50 and bigger the 0, then...
if (!((x <= 50 && x >= 0) && (y_Plus_One <= 50 && y_Plus_One >= 0))) {
// then print " lost! "
document.write("LOST!" + "<br />");
// & keep the record of the x and y_Plus_One value to the lost_Robot_Scent array
lost_Robot_Scent.push([x, y]);
// and return false - this stops printing "Lost!" more than one times
return false;
// Otherwise, if the above doesn't satisfy, then...
} else {
// variable result instantiated with the updated coordinates (y_Plus_One)
var result = " | ( " + x + ", " + y_Plus_One + " ) " + " | " + orientation + " " + "<br />";
}
}
}
//print the result
document.write(result);
// if none of the if...statement above satisfy, then...
} else {
// variale lost instantiated with "Lost!" message
var lost = "LOST!" + "<br />";
// push the robot to the lost_Robot_Scent
lost_Robot_Scent.push("| ( " + x + ", " + y + " ) " + "<br />");
}
} else {
alert("There is alot of of instructions given. Please make sure that the instruction is less than 100 instructions");
}
}
}
// new Robot object initialised
var one = new Robot_Coordinatation(50, 50, orientation[1]);
one.Robot_Instruction("LRLRLRLRLRLLRRLRLRLLRLLRRLL");
var two = new Robot_Coordinatation(20, 30, orientation[3]);
two.Robot_Instruction("FFFLLFLRLFLRFLRLLLFRL");
var two = new Robot_Coordinatation(30, 7, orientation[3]);
two.Robot_Instruction("FFFFLRLFLRFLRL");
Maintaining lost_Robot_Scent
I can help you with keeping a collection of locations where your robots get lost (your lost_Robot_Scent array). I suggest using a Set instead on an Array. Sets provide O(1) insertion and O(1) lookup. This probably isn't a big deal in this situation, but it's good to know about Set anyway.
The main problem you'll run into is that array equality is pointer equality: for example, [1, 1] === [1, 1] returns false. One workaround is using toString() on the arrays and storing that in the Set. For example:
var lost_Robot_Scent = new Set();
lost_Robot_Scent.add( [1, 1].toString() );
lost_Robot_Scent.has( [1, 1].toString() ); // -> true
lost_Robot_Scent.has( [2, 2].toString() ); // -> false
I don't know if this is the cleanest solution, but it works. If you want to use an Array instead of a Set, just use push instead of add and includes (or indexOf) instead of has, e.g.
var lost_Robot_Scent = [];
lost_Robot_Scent.push( [1, 1].toString() );
lost_Robot_Scent.includes( [1, 1].toString() ); // -> true
lost_Robot_Scent.includes( [2, 2].toString() ); // -> false
If you are worried about performance, you can test these two methods against each other in specific contexts.
Improve The Code
One thing you can do to simplify your code is to lessen the nested if statements. For example, the first if in your Robot_Instruction function could be
if (instruct_The_Robot.length > 100) {
alert("Too many instructions! Please limit to 100."
return;
}
// continue...
Perhaps this is a bit off-topic, but you should only use comments for things are aren't obvious. For example, variable Left declared and instantiated with -90° is unnecessary.
One last thing: you can simplify the "instructions" loop using a switch statement instead of if/else blocks. Or, if you want to make is super-readable, you can use a JavaScript object like so:
var move = {
L: function() {
// turn left
},
R: function() {
// turn right
},
F: function() {
// move forward
},
};
// then, in the "instructions" loop, you can just do
for (var i = 0; i < instruct_The_Robot.length; i++) {
move[ instruct_The_Robot[i] ]();
}
That's a pretty neat trick.
How to prevent a new robots from getting lost in the same places as old robots
Assuming you've fixed your bugs, and robots are moving. When you determine that a robot is moving forward, you have to determine if the new coordinates are already in the lost_Robot_Scent array. You can do this using something like the following:
var robotLostAtSameLocation = false;
for (var i = 0; i < lost_Robot_Scent.length; i++) {
var lostRobotLocation = lost_Robot_Scent[i];
if(lostRobotLocation[0] === x && lostRobotLocation[1] === y) {
robotLostAtSameLocation = true;
break;
}
}
if (robotLostAtSameLocation) {
// whatever you want to do in this case
}
else {
// whatever you want to do in this case
}
Simple optimization
Note that you can get rid of this loop if you change the lost_Robot_Scent array from containing [x,y] to containing something like 'x:y'. So rather than an array that contains other arrays looking like this: [[39,51], [51,15], [-1,11]], it will be an array containing strings looking like: ['39:51', '51:15', '-1:11']. What this buys you is that you can then just say var robotLostAtSameLocation = lost_Robot_Scent.indexOf(x + ':" + y) > -1;
Recommendation
Change var instruction = ["L", "R", "F"]; into something more like var INSTRUCTIONS = {LEFT: 'L', RIGHT: 'R', FORWARD: 'F'};. This turns lines like instruct_The_Robot[i] === instruction[0] into instruct_The_Robot[i] === INSTRUCTIONS.LEFT, improving readability.
Bugs
You are never updating x, y, or orientation. Your robots are never moving. You are only outputting a string.
You are only checking if the y-coordinate is out of bounds. You are forgetting to check if the x-coordinate is out of bounds.
You are pushing [x,y] into the lost_Robot_Scent array on one line, then pushing "| ( " + x + ", " + y + " ) " + "<br />" into the same array on another line. Don't do that. It's hard to reason about a program when it is not consistent.
There may be other issues - I can't take the time to fully digest it at the moment.

Result of a while loop still happens even when the condition isn't met

I'm practising writing Javascript by making a Roguelike dungeon game but there is a problem when I want to create monsters. I have written a while loop such as:
this.getRandomCoordinatesInRoom = function(roomNumber) {
var validLocationFound = false;
while (!validLocationFound){
// Generate co-ords in room first
x = Math.floor(Math.random() * (this.roomList[roomNumber].width) + (this.roomList[roomNumber].posX));
y = Math.floor(Math.random() * (this.roomList[roomNumber].height) + (this.roomList[roomNumber].posY));
// Find location of (x,y) in Dungeon Array
//alert(arrayLocation);
var tmpX = ((this.roomList[roomNumber]).posX + x);
var tmpY = ((this.roomList[roomNumber]).posY + y);
var arrayLocation = ((tmpY * 80) + tmpX);
//var arrayLocation = ((this.roomList[roomNumber].posX + x) + (80 * (this.roomList[roomNumber].posY + y)));
if (this.dungeonArray[(tmpY + tmpX)] === "floor") {
validLocationFound = true;
};
if ((x<this.roomList[roomNumber].posX) || (x>(this.roomList[roomNumber].posX + this.roomList[roomNumber].width))){
alert("x out of bounds");
};
if ((y<this.roomList[roomNumber].posY) || (y>(this.roomList[roomNumber].posY + this.roomList[roomNumber].height))){
alert("y out of bounds");
};
writeToScreen("Room upper left corner = " + (this.roomList[roomNumber].posX).toString() + "," + (this.roomList[roomNumber].posY).toString(),10);
return [x,y];
if (!(getTileAt(arrayLocation) === "floor")){
alert("It messed up");
}
};
The code randomly generates an x,y coordinate and converts it to a single number (My dungeon array is one dimensional, 0-79 across and then 80 is a new row). however, even when the code generates a coordinate that isn't valid (!= "floor"), it still finishes the function as though it returned true. Why is this?
Your function returns [x,y] from inside the while loop. Declare the variables outside of the loop and then return the value from outside the loop. Or else, return is when validLocationFound is true.
var x, y ;
while(...) {
...
}
return [x, y];

Raphael JS - maintain path between two objects

I've created a plugin for Raphael JS. It basically allows you to call
paper.connect(obj1,obj2,colour)
That draws a line between the two objects and maintains the line when the objects are animated.
This is what I've come up with so far. It works but its not very performant, any suggestions on what else I could do to achieve the same thing.
Raphael.fn.connect = function(obj1, obj2, colour) {
// list of paths each object has
obj1.connections = []
obj2.connections = []
// get the bounding box of each object
var box1 = obj1.getBBox()
var box2 = obj2.getBBox()
// create a line/path from object 1 to object 2
var p = this.path("M" + (box1.x + box1.width / 2) + ","
+ (box1.y + box1.height / 2) + "L" + (box2.x + box2.width / 2)
+ "," + (box2.y + box2.height / 2))
// adjust attributes of the path
p.attr({
stroke : colour,
"stroke-linecap" : "round",
"stroke-opacity" : Math.max(obj1.attr('opacity'), obj2.attr('opacity'))
})
// set the start and end element for this path
p.startElement = obj1;
p.endElement = obj2;
// add the path to each of the object
obj1.connections.push(p)
obj2.connections.push(p)
// mark each object as being connected
obj1.connected = true;
obj2.connected = true;
// listen for the Raphael frame event
eve.on("raphael.anim.frame.*", function(obj) {
// if the object the frame event is fired on is connected
if (this.connected) {
// for each connection on this object
for ( var c in this.connections) {
var path = this.connections[c]; // temp path
var b1 = path.startElement.getBBox(); // get the current
// location of start
// element
var b2 = path.endElement.getBBox();// get the current location
// of end element
// move the path to the new locations
path.attr({
path : "M " + (b1.x + b1.width / 2) + " "
+ (b1.y + b1.height / 2) + "L "
+ (b2.x + b2.width / 2) + " "
+ (b2.y + b2.height / 2),
opacity : Math.max(path.startElement.attr('opacity'),
path.endElement.attr('opacity'))
});
}
}
});
}
Not convinced this is the best way at all, but this is my first time using Raphael so I just did all that from looking at the Raphael source code...
In our app we have a line tool. We drop a line with 2 movable end points onto our paper.
All shapes in our app have an associated VisualModel that contains all the geometric data inside of them. These VisualModels also double as Actors. Any Actor can subscribe to any other Actor and when changes occur all interested parties respond.
A system like this allows for a line's path to change via a redraw function that gets called anytime the 2 connected objects modify their X/Y coordinates.
connecting_line.js (redraw)
redraw: function() {
var x1 = this.shapeView1.visualModel.get('x'),
y1 = this.shapeView1.visualModel.get('y'),
x2 = this.shapeView2.visualModel.get('x'),
y2 = this.shapeView2.visualModel.get('y'),
pathData;
pathData = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
this.line.attr({
path: pathData,
fill: '#000000',
stroke: LineConstants.COLOR,
'stroke-width': LineConstants.THICKNESS
});
}
We created "movable" mixin. This mixin would allow you to add movability to your shapes. This mixin would update the x/y coordinates in and in turn trigger a 'change' event that your line class would pick up.
movable.js
handleDraggging: function(delta) {
this.shape.move(delta);
}
move: function(delta) {
//... compute movement based on delta
this.visualModel.set('x', xPosition);
this.visualModel.set('y', yPosition);
}
connecting_line.js
initialize: function(shapeView1, shapeView2) {
// ...
this.shapeView1 = shapeView1;
this.shapeView2 = shapeView2;
this.listenTo(shapeView1.visualModel, 'change:x change:y', this.redraw);
this.listenTo(shapeView2.visualModel, 'change:x change:y', this.redraw);
}
Performance for this is great. You can take a look at it in action by going to eventbrite.com, create an event, enabling reserved seating (step 2), add a new map, click 'objects' on the left and drop a line on the paper.

Categories

Resources