I'm working in canvas to take information and plot it onto a graph. Eventually it will go to php and retrieve the data from a server, but for now I just need it to plot any data correctly.
I have the canvas drawn out how I'd like it and began plotting the data, but when I do it doesn't give me a thin path, it's more like a giant blob that covers everything. When looking at my code, it's important to know that it is mostly just initialization of the canvas, but I need to post mostly all of it in order to give context for what is happening in the program.
var canvas ;
var context ;
var Val_max;
var Val_min;
var sections;
var xScale;
var yScale;
var Apple = [10.25,10.30,10.10,10.20];
function init() {
Val_max = 10.5;
Val_min = 10;
var stepSize = .049999999999999; //.5 results in inaccurate results
var columnSize = 50;
var rowSize = 20;
var margin = 20;
var xAxis = [" "," "," ", " ", " ", "10AM", " ", " ", " ", " ", " ", "11AM", " ", " ", " ", " ", " ", "12PM", " ", " ", " ", " ", " ", "1PM", " ", " ", " ", " ", " ", "2PM", " ", " ", " ", " ", " ", "3PM", " ", " ", " ", " ", " ", "4PM"];
sections = xAxis.length-1;
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
context.fillStyle = "#808080";
yScale = (canvas.height - columnSize - margin) / (Val_max - Val_min); // Total height of the graph/range of graph
xScale = (canvas.width - rowSize - margin) / sections; // Total width of the graph/number of ticks on the graph
context.strokeStyle="#808080"; // color of grid lines
context.beginPath();
// print Parameters on X axis, and grid lines on the graph
context.moveTo(xScale+margin, columnSize - margin);
context.lineTo(xScale+margin, columnSize + (yScale * 10 * stepSize) - margin); //draw y axis
for (i=1;i<=sections;i++) {
var x = i * xScale;
context.moveTo(x + margin, columnSize + (yScale * 10 * stepSize) - margin);
context.lineTo(x + margin, columnSize + (yScale * 10 * stepSize) - margin - 5); //draw ticks along x-axis
context.fillText(xAxis[i], x,canvas.height - margin); //Time along x axis
}
// print row header and draw horizontal grid lines
var count = 0;
context.moveTo(xScale+margin, 260);
context.lineTo(canvas.width - margin, 260); // draw x axis
for (scale=Val_max;scale>=Val_min;scale = scale - stepSize) {
scale = scale.toFixed(2);
var y = columnSize + (yScale * count * stepSize) - margin;
context.fillText(scale, margin - 20,y);
context.moveTo(xScale+margin, y);
context.lineTo(xScale+margin+5, y); //Draw ticks along y-axis
count++;
}
context.stroke();
context.translate(rowSize,canvas.height + Val_min * yScale);
context.scale(1,-1 * yScale);
// Color of each dataplot items
context.strokeStyle="#FF0066";
//plotData(Apple);
context.strokeStyle="#9933FF";
//plotData(Samsung);
context.strokeStyle="#000";
//plotData(Nokia);
}
Ok that's the initialization of the canvas, I know it's messy but I think I'll have to reference something from it for the next function.
function plotData(dataSet) {
var margin = 20;
context.beginPath();
context.moveTo(xScale+margin, dataSet[0]);
for (i=0;i<sections;i++) {
context.lineTo(i * xScale + margin, dataSet[i]);
}
context.stroke();
}
This function is supposed to take the data from the array and plot it on the graph. I can get it to draw, but it's not a thin line. Here's a picture of the blob that I'm getting.
It also doesn't seem to be accurately plotting the coordinates from my array either.
I know this question is pretty in depth, but any help would be very appreciated!
The translate and scale are applied to the current transform. Each time you call them you translate and scale a little more.
Use save and restore to get back the original transform.
context.save(); // <--------------------- added
context.translate(rowSize,canvas.height + Val_min * yScale);
context.scale(1,-1 * yScale);
// Color of each dataplot items
context.strokeStyle="#FF0066";
//plotData(Apple);
context.strokeStyle="#9933FF";
//plotData(Samsung);
context.strokeStyle="#000";
//plotData(Nokia);
context.restore(); // <-------------------- added
Related
I have a for loop that returns a decimal between 0 and 1. I'd like to make a curve that appears more like a rounded corner than it is now. I'd also like to have it start ramping up only after 0.25. I can't quite figure out how to do it with the math I have now. I'm using Math.log and a linear conversion function, but maybe I need something more related to a parabolic curve.
for (i = 1; i < 101; ++i) {
var dec = i / 100
if (dec >= 0.25) {
console.log("dec = " + dec);
var large = i * 100
var log = Math.log(large);
console.log("log = " + log);
var linCon = applyLinearConversion(log, 2.8, 9.2104, -2.7, 1)
console.log("linCon " + i + " = " + linCon);
document.getElementById("graph").innerHTML += "<div style='background-color:#000000; width:" + (linCon * 1000) + "px; height:5px;'></div>";
}
}
function applyLinearConversion(OldValue, OldMin, OldMax, NewMin, NewMax) {
OldRange = (OldMax - OldMin)
if (OldRange == 0)
NewValue = NewMin
else {
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
return NewValue
}
<div id="graph"></div>
I have it populating a div with more styled divs.
Mine is like this:
I want mine more like this:
You can use the formula of the half circle graph which is:
It results in the following graph:
Since you are using horizontal divs that are stacked vertically to draw the graph, the x and y coordinates will be reversed and the left quarter of the circle will be used from the above graph.
var width = 200; // the width of the graph
var height = 200; // the height of the graph
var xOffset = 0.25 * width; // the x offset at which the graph will start ramping up (this offset is added to the graph width)
var html = ""; // to accumulate the generated html before assigning it to innerHTML (it's not a good idea to constantly update innerHTML)
for (i = 1; i < 101; ++i) {
var x = 1 - i / 100; // the x coordinate, we are using the left side of the graph so x should be negative going from -1 to 0
var y = Math.sqrt(1 - x * x); // the y coordinate as per the formula (this will be used for the width)
html += "<div style='background-color:#000000; width:" + (xOffset + y * width) + "px; height:" + (height / 100) + "px;'></div>";
}
document.getElementById("graph").innerHTML = html;
<div id="graph"></div>
I have a page that shows a grid of job positions and I am showing the progression from one to another by using SVG + paths to draw the connection between boxes.
My code is working just fine when I am connecting an element at the top to one at the bottom. It is finding the XY of the top box and the XY of the bottom box and connects the two.
My issue is I want to flip this code and go from the bottom up. This means I need the top XY of the bottom element and the bottom XY of the top element and draw the path.
I have been trying to flip offsets around and basically do the opposite of what is working but I think my math is wrong somewhere.
Here is what the top down approach looks like. Works just fine.
The bottom up approach however is not correct. Theres some math errors somewhere and the calculations are causing the SVG to be cut off.
I believe the answer lies within the connectElements() function as that is where the coordinates are determined.
Any thoughts on how I can get these calculations corrected?
Fiddle: http://jsfiddle.net/Ly59a2hf/2/
JS Code:
function getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
function drawPath(svg, path, startX, startY, endX, endY) {
// get the path's stroke width (if one wanted to be really precize, one could use half the stroke size)
var style = getComputedStyle(path)
var stroke = parseFloat(style.strokeWidth);
// check if the svg is big enough to draw the path, if not, set heigh/width
if (svg.getAttribute("height") < endY) svg.setAttribute("height", endY);
if (svg.getAttribute("width") < (startX + stroke)) svg.setAttribute("width", (startX + stroke));
if (svg.getAttribute("width") < (endX + stroke * 3)) svg.setAttribute("width", (endX + stroke * 3));
var deltaX = (endX - startX) * 0.15;
var deltaY = (endY - startY) * 0.15;
// for further calculations which ever is the shortest distance
var delta = deltaY < absolute(deltaX) ? deltaY : absolute(deltaX);
// set sweep-flag (counter/clock-wise)
// if start element is closer to the left edge,
// draw the first arc counter-clockwise, and the second one clock-wise
var arc1 = 0;
var arc2 = 1;
if (startX > endX) {
arc1 = 1;
arc2 = 0;
}
// draw tha pipe-like path
// 1. move a bit down, 2. arch, 3. move a bit to the right, 4.arch, 5. move down to the end
path.setAttribute("d", "M" + startX + " " + startY +
" V" + (startY + delta) +
" A" + delta + " " + delta + " 0 0 " + arc1 + " " + (startX + delta * signum(deltaX)) + " " + (startY + 2 * delta) +
" H" + (endX - delta * signum(deltaX)) +
" A" + delta + " " + delta + " 0 0 " + arc2 + " " + endX + " " + (startY + 3 * delta) +
" V" + (endY - 30));
}
function connectElements(svg, path, startElem, endElem, type, direction) {
// Define our container
var svgContainer = document.getElementById('svgContainer'),
svgTop = getOffset(svgContainer).top,
svgLeft = getOffset(svgContainer).left,
startX,
startY,
endX,
endY,
startCoord = startElem,
endCoord = endElem;
console.log(svg, path, startElem, endElem, type, direction)
/**
* bottomUp - This means we need the top XY of the starting box and the bottom XY of the destination box
* topDown - This means we need the bottom XY of the starting box and the top XY of the destination box
*/
switch (direction) {
case 'bottomUp': // Not Working
// Calculate path's start (x,y) coords
// We want the x coordinate to visually result in the element's mid point
startX = getOffset(startCoord).left + 0.5 * getOffset(startElem).width - svgLeft; // x = left offset + 0.5*width - svg's left offset
startY = getOffset(startCoord).top + getOffset(startElem).height - svgTop; // y = top offset + height - svg's top offset
// Calculate path's end (x,y) coords
endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
endY = endCoord.getBoundingClientRect().top - svgTop;
break;
case 'topDown': // Working
// If first element is lower than the second, swap!
if (startElem.offsetTop > endElem.offsetTop) {
var temp = startElem;
startElem = endElem;
endElem = temp;
}
// Calculate path's start (x,y) coords
// We want the x coordinate to visually result in the element's mid point
startX = getOffset(startCoord).left + 0.5 * getOffset(startElem).width - svgLeft; // x = left offset + 0.5*width - svg's left offset
startY = getOffset(startCoord).top + getOffset(startElem).height - svgTop; // y = top offset + height - svg's top offset
// Calculate path's end (x,y) coords
endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
endY = endCoord.getBoundingClientRect().top - svgTop;
break;
}
// Call function for drawing the path
drawPath(svg, path, startX, startY, endX, endY, type);
}
function connectAll(direction) {
var svg = document.getElementById('svg1'),
path = document.getElementById('path1');
// This is just to help with example.
if (direction == 'topDown') {
var div1 = document.getElementById('box_1'),
div2 = document.getElementById('box_20');
} else {
var div1 = document.getElementById('box_20'),
div2 = document.getElementById('box_1');
}
// connect all the paths you want!
connectElements(svg, path, div1, div2, 'line', direction);
}
//connectAll('topDown'); // Works fine. Path goes from the bottom of box_1 to the top of box_20
connectAll('bottomUp'); // Doesn't work. I expect path to go from top of box_20 to the bottom of box_1
IMO, you can simplify things by making the SVG the exact right size. Ie. fit it between the two elements vertically, and have it start at the leftmost X coord.
If you do that, the path starts and ends at either:
X: 0 or svgWidth
Y: 0 or svgHeight.
Then as far as drawing the path goes, it's just a matter of using the relative directions (startX -> endX and startY -> endY) in your calculations. I've called these variables xSign and ySign. If you are consistent with those, everything works out correctly.
The last remaining complication is working out which direction the arcs for the rounded corners have to go - clockwise or anticlockwise. You just have to work out the first one, and the other one is the opposite.
function getOffset(el) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
function drawPath(svg, path, start, end) {
// get the path's stroke width (if one wanted to be really precise, one could use half the stroke size)
var style = getComputedStyle(path)
var stroke = parseFloat(style.strokeWidth);
var arrowHeadLength = stroke * 3;
var deltaX = (end.x - start.x) * 0.15;
var deltaY = (end.y - start.y) * 0.15;
// for further calculations which ever is the shortest distance
var delta = Math.min(Math.abs(deltaX), Math.abs(deltaY));
var xSign = Math.sign(deltaX);
var ySign = Math.sign(deltaY);
// set sweep-flag (counter/clock-wise)
// If xSign and ySign are opposite, then the first turn is clockwise
var arc1 = (xSign !== ySign) ? 1 : 0;
var arc2 = 1 - arc1;
// draw tha pipe-like path
// 1. move a bit vertically, 2. arc, 3. move a bit to the horizontally, 4.arc, 5. move vertically to the end
path.setAttribute("d", ["M", start.x, start.y,
"V", start.y + delta * ySign,
"A", delta, delta, 0, 0, arc1, start.x + delta * xSign, start.y + 2 * delta * ySign,
"H", end.x - delta * xSign,
"A", delta, delta, 0, 0, arc2, end.x, start.y + 3 * delta * ySign,
"V", end.y - arrowHeadLength * ySign].join(" "));
}
function connectElements(svg, path, startElem, endElem, type, direction) {
// Define our container
var svgContainer = document.getElementById('svgContainer');
// Calculate SVG size and position
// SVG is sized to fit between the elements vertically, start at the left edge of the leftmost
// element and end at the right edge of the rightmost element
var startRect = getOffset(startElem),
endRect = getOffset(endElem),
pathStartX = startRect.left + startRect.width / 2,
pathEndX = endRect.left + endRect.width / 2,
startElemBottom = startRect.top + startRect.height,
svgTop = Math.min(startElemBottom, endRect.top + endRect.height),
svgBottom = Math.max(startRect.top, endRect.top),
svgLeft = Math.min(pathStartX, pathEndX),
svgHeight = svgBottom - svgTop;
// Position the SVG
svg.style.left = svgLeft + 'px';
svg.style.top = svgTop + 'px';
svg.style.width = Math.abs(pathEndX - pathStartX) + 'px';
svg.style.height = svgHeight + 'px';
// Call function for drawing the path
var pathStart = {x: pathStartX - svgLeft, y: (svgTop === startElemBottom) ? 0 : svgHeight};
var pathEnd = {x: pathEndX - svgLeft, y: (svgTop === startElemBottom) ? svgHeight : 0};
drawPath(svg, path, pathStart, pathEnd);
}
function connectAll(direction) {
var svg = document.getElementById('svg1'),
path = document.getElementById('path1');
// This is just to help with example.
if (direction == 'topDown') {
var div1 = document.getElementById('box_1'),
div2 = document.getElementById('box_20');
} else {
var div1 = document.getElementById('box_20'),
div2 = document.getElementById('box_1');
}
// connect all the paths you want!
connectElements(svg, path, div1, div2, 'line');
}
//connectAll('topDown');
connectAll('bottomUp');
http://jsfiddle.net/93Le85tk/3/
So I created a .js file to calculate the area of a circle and calculateArea() needs to calculate it.
The only thing that it does is the prompt(). What am I doing wrong?
function calculateArea(myRadius){
var area = (myRadius * myRadius * Math.PI);
return area;
function MyArea(){
calculateArea(myRadius);
alert("A circle with a " + myRadius +
"centimeter radius has an area of " + area +
"centimeters. <br>" + myRadius +
"represents the number entered by the user <br>" + area +
"represents circle area based on the user input.");
}
}
var myRadius = parseFloat(prompt("Enter the radius of your circle in cm:",0));
calculateArea(myRadius);
You need to keep function MyArea outside calculateArea and call calculateArea from within MyArea.
Call MyArea function instead of calculateArea.
Example Snippet:
function calculateArea(myRadius) {
return (myRadius * myRadius * Math.PI);
}
function MyArea() {
var area = calculateArea(myRadius);
alert("A circle with a " + myRadius + "centimeter radius has an area of " + area + "centimeters. <br>" + myRadius + "represents the number entered by the user <br>" + area + "represents circle area based on the user input.");
}
var myRadius = parseFloat(prompt("Enter the radius of your circle in cm:", 0));
MyArea(myRadius);
PS: There are better ways to do this. Comment in case of questions.
this is a way for calculate the circle area
let Area, Environment;
let Radius = prompt("Enter Radius ");
function calculate(Radius) {
CalEnvironment(Radius);
CalArea(Radius);
}
function CalEnvironment(Radius) {
Environment = Radius * 3.14 * 2;
console.log("Environment is : " + Environment);
}
function CalArea(Radius) {
Area = Radius * Radius * 3.14;
console.log("Area is : " + Area);
}
calculate(Radius);
You basically need to call MyArea outside of calculateArea but in this case, why not something like this?
function calculateArea(myRadius) {
return myRadius * myRadius * Math.PI;
}
var myRadius = parseFloat(prompt("Enter the radius of your circle in cm:",0));
var area = calculateArea(myRadius);
alert("A circle with a " + myRadius + "centimeter radius has an area of " + area + "centimeters. <br>" + myRadius + "represents the number entered by the user <br>" + area + "represents circle area based on the user input.");
The following is a single function solution:
function MyArea(myRadius){
var area = Math.pow(myRadius, 2) * Math.PI;
alert(
"A circle with a " + myRadius +
"centimeter radius has an area of " +
area + "centimeters. \n" + myRadius +
"represents the number entered by the user \n" +
area + "represents circle area based on the user input."
);
}
var myRadius = parseFloat(prompt("Enter the radius of your circle in cm:", 0));
MyArea(myRadius);
I'm trying to program some animations in html5 canvas. I need the animations to be reproduced on any other client connected to my server. So what I do is I send the function to be called and the arguments as a string and call eval() on the client side. That way the animation logic needs to be done only on one canvas, while the function calls that actually render things are executed by all clients.
However, my frame rates drop drastically when I do this. I use socket.emit() to send signals to the server which in turn calls socket.broadcast.emit() to send the string to all clients. This is the rendering loop :
var rf = function()
{
// clear background
context.fillStyle = "#000";
context.fillRect(0, 0, width, height);
socket.emit('action', 'clearScreen', "{}");
// mouse position to head towards
var cx = (mousex - width / 2) + (width / 2),
cy = (mousey - height / 2) + (height / 2);
// update all stars
var sat = Floor(Z * 500); // Z range 0.01 -> 0.5
if (sat > 100) sat = 100;
for (var i=0; i<units; i++)
{
var n = stars[i], // the star
xx = n.x / n.z, // star position
yy = n.y / n.z,
e = (1.0 / n.z + 1) * 2; // size i.e. z
if (n.px !== 0)
{
// hsl colour from a sine wave
context.strokeStyle = "hsl(" + ((cycle * i) % 360) + "," + sat + "%,80%)";
context.lineWidth = e;
context.beginPath();
socket.emit('action', 'context.beginPath', "{}");
context.moveTo(xx + cx, yy + cy);
socket.emit('action', 'context.moveTo', "{\"a\": [" + (xx + cx) + "," + (yy + cy) + "]}");
context.lineTo(n.px + cx, n.py + cy);
socket.emit('action', 'context.lineTo', "{\"a\": [" + (n.px + cx) + "," + (n.py + cy) + "]}");
context.stroke();
socket.emit('action', 'context.stroke', "{}");
}
// update star position values with new settings
n.px = xx;
n.py = yy;
n.z -= Z;
// reset when star is out of the view field
if (n.z < Z || n.px > width || n.py > height)
{
// reset star
resetstar(n);
}
}
// colour cycle sinewave rotation
cycle += 0.01;
requestAnimFrame(rf);
};
requestAnimFrame(rf);
The above snippet was taken from here.
Can you suggest ways to prevent the frame rates from dropping? I guess this can be done if socket.emit was non-blocking.
Sending strings that reproduces the frame is the lightest way to accomplish what i want. Sending pixels are even more heavy. Sending strings works fine when the frame is easy to draw - for example a simple circle moving up and down renders fine.
I've been down the road you're traveling now. It's an interesting & fun road, but sometimes a frustrating road. Have fun and be patient!
OK...here are a few hints:
All your drawing commands must be atomic. Each command sent to any client must define a complete drawing operation (a complete path operation from beginPath through stroke).
Make your clients smart. Give each client at least enough javascript smarts to draw each primitive shape after being given a primitive definition. Client side functions: drawLine(), drawRect(), drawCircle(), drawBCurve(), drawQCurve(), drawText(), etc.
Emits can be lost. This is why it's not a good idea to just send raw context commands. Include a serial index# in each command object and, after processing each command array, append that new array to a master array (the master array contains all arrays ever received). This way the client can recognize and request replacements of missing packets. Hint: you can even use this master array to replay the entire animation ;-)
Here are some example snippets which expand my hints (not complete or tested!):
On the computer issuing the drawing commands
// emits can be lost
// include an index# with each command so clients
// can request replacements for lost commands
var nextCommand=1;
// an array to hold all commands to be sent with the next emit
var commands=[];
// Example: push 1 atomic line command into the commands array
commands.push({
op:'line',
x0:xx+cx,
y0:yy+cy,
x1:n.px+cx,
y1:n.py+cy,
stroke:"hsl("+((cycle*i)%360)+","+sat+"%,80%)",
fill:null,
index:(nextCommand++),
});
// Continue adding commands to be sent in this emit
// Push any more atomic drawing commands into commands[]
// You will probably generate many commands through a loop
// serialize the commands array and emit it
socket.emit(JSON.stringify(commands));
On each client
// context color changes are expensive
// Don't change the color if the context is already that color
// These vars hold the current context color for comparison
var currentStroke='';
var currentFill='';
// deserialize the incoming commands back into an array of JS command objects
var commands=JSON.parse(receivedCommands);
// process each command in the array
for(var i=0;i<commands.length;i++){
var cmd=commands[i];
// execute each command's atomic drawing based on op-type
switch(cmd.op){
case 'line':
drawLine(cmd);
break;
// ... also 'circle','rect',etc.
}
}
// draw a line defined by an atomic line drawing command
function drawLine(cmd){
if(stroke){
// execute primitive line commands
context.beginPath();
context.moveTo(cmd.x0,cmd.y0);
context.lineTo(cmd.x1,cmd.y1);
// Don't change the color if the context is already that color
if(stroke!==currentStroke){
context.strokeStyle=stroke;
currentStroke=stroke;
}
// stroke the line (this completes an atomic line draw--beginPath thru stroke)
context.stroke();
}
}
Emit only once per frame, sending an object actions containing all the informations
var rf = function()
{
var actions = {};//prepare the object to be sent
// clear background
context.fillStyle = "#000";
context.fillRect(0, 0, width, height);
//socket.emit('action', 'clearScreen', "{}");
actions['clearScreen'] = "{}";
// mouse position to head towards
var cx = (mousex - width / 2) + (width / 2),
cy = (mousey - height / 2) + (height / 2);
// update all stars
var sat = Floor(Z * 500); // Z range 0.01 -> 0.5
if (sat > 100) sat = 100;
actions['stars'] = [];//push all the star related actions in this array
for (var i=0; i<units; i++)
{
var n = stars[i], // the star
xx = n.x / n.z, // star position
yy = n.y / n.z,
e = (1.0 / n.z + 1) * 2; // size i.e. z
if (n.px !== 0)
{
// hsl colour from a sine wave
context.strokeStyle = "hsl(" + ((cycle * i) % 360) + "," + sat + "%,80%)";
context.lineWidth = e;
context.beginPath();
//socket.emit('action', 'context.beginPath', "{}");
actions['stars'].push({
'context.beginPath' : "{}"
});
context.moveTo(xx + cx, yy + cy);
//socket.emit('action', 'context.moveTo', "{\"a\": [" + (xx + cx) + "," + (yy + cy) + "]}");
actions['stars'].push({
'context.moveTo' : "{\"a\": [" + (xx + cx) + "," + (yy + cy) + "]}"
});
context.lineTo(n.px + cx, n.py + cy);
//socket.emit('action', 'context.lineTo', "{\"a\": [" + (n.px + cx) + "," + (n.py + cy) + "]}");
actions['stars'].push({
'context.lineTo' : "{\"a\": [" + (n.px + cx) + "," + (n.py + cy) + "]}"
});
context.stroke();
//socket.emit('action', 'context.stroke', "{}");
actions['stars'].push({
'context.stroke' : "{}"
});
}
// update star position values with new settings
n.px = xx;
n.py = yy;
n.z -= Z;
// reset when star is out of the view field
if (n.z < Z || n.px > width || n.py > height)
{
// reset star
resetstar(n);
}
}
// colour cycle sinewave rotation
cycle += 0.01;
//emit only once
socket.emit('actions',actions);
requestAnimFrame(rf);
};
//requestAnimFrame(rf);
rf();//call directly
I have a paper with 400 x 500 in size. I am trying to divide this into 20 x 20 pixels with below code
var dpH = 500, dpW = 400, drawPad = new Raphael(document.getElementById('p'),
dpW, dpH);
for ( var i = 0; i <= dpH / 20; i++) {
drawPad.path("M" + 1 + " " + ((i * 20) + 1) + "L" + dpW + " "
+ ((i * 20) + 1));
}
for ( var j = 0; j <= (dpW / 20); j++) {
drawPad.path("M" + ((j * 20) + 1) + " " + 1 + "L" + ((j * 20) + 1) + " "
+ dpH);
}
And HTML markup is like below
<div id="p" style="background-image:url(image.png)"> </div>
with same height and width of Background Image.
My original requirement was making the image.png as Rapheal paper. But I was failed to do that. So I made it as background-image to the DIV#P. Then converted the DIv to Paper.
Here are my questions related to above
Does all the pixels of Background-Image and DIV match with each other?
The way I did above is to classify the total paper into 20x20 pixel divisions. Is that correct way of doing?
What is the width of the drawn line?
Please help me on this.
Ok, so if I understand you correctly; What you really want is to get the raw image data for 20x20 squares of the image.
Here's how you can extract image data with Canvas (also on jsFiddle):
var dpH = 500,
dpW = 400,
ctx = document.getElementById('p').getContext('2d'),
exportData = function() {
var data;
for (var y=0, yl=dpH/20; y<yl; y++) {
for (var x=0, xl=dpW/20; x<xl; x++) {
imgData = ctx.getImageData(x*20, y*20, 20, 20).data;
console.log("Image data for " + x*20 + ", " + y*20, imgData);
// data is an array with 4 values pr pixel
// Top left pixel in the 20x20 square
r = imgData[0]; // red
g = imgData[1]; // green
b = imgData[2]; // blue
a = imgData[3]; // alpha
console.log("RGBa of " + x*20 + ", " + y*20 + ": ", r, g, b, a);
}
}
},
drawImage = function() {
ctx.drawImage(this, 0, 0);
exportData(this);
};
var img = new Image();
img.onload = drawImage;
img.src = "image.png"; // has to be on the same domain
** Original answer **
The result is a DIV with an SVG-element inside, and a background image behind it. The browser (if it supports SVG) will render them on top of each other. Do you want to extract pixel values? If so, you have to do this through HTML5 Canvas instead of SVG.
Sorry, I don't understand. What are you trying to accomplish? Do you want the pixel data for 20x20 squares? With Raphael you are just drawing lines on top of the picture.
The defaut with of a path is 1 pixels. You can change this by setting an attribute on the path. Example (also on jsfiddle.net):
var dpH = 500,
dpW = 400,
drawPad = Raphael(document.getElementById('p'), dpW, dpH),
style = {
"stroke" : "#fff", // white
"stroke-width" : 2 // default 1
};
for ( var i = 0; i <= dpH / 20; i++) {
drawPad.path("M" + 1 + " " + ((i * 20) + 1) + "L" + dpW + " "
+ ((i * 20) + 1)).attr(style);
}
for ( var j = 0; j <= (dpW / 20); j++) {
drawPad.path("M" + ((j * 20) + 1) + " " + 1 + "L" + ((j * 20) + 1) + " "
+ dpH).attr(style);
}