Issues with drawing reading values in javascript array - drawing in HTML5 canvas - javascript

I'm relatively new to all this and am trying to draw a basic shape on the html5-canvas. I think an option is to use 3.js for this but I was wondering if it's possible to do it without? The x,y values for each point are in arrays... Please help! Code and fiddle link below:
http://jsfiddle.net/mewchew/wJwL8/8/
var canvas = document.getElementById("myCanvas");
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var width = canvas.width
var height = canvas.height
var xProp = 0.28
var yProp = 0.43
//Find canvas centerpoint - may need to change to global variable?
function centerPoint(width, height) {
x = Number(width) / 2;
y = Number(height) / 2;
return [x, y];
}
//Define diamond points
xy = centerPoint(width,height);
var pTx = newArray();
pTx[0] = x;
pTy[1] = x + xProp*x;
pTy[2] = x;
pTy[3] = x - xProp*x;
pTy[4] = x;
var pTy = newArray();
pTy[0] = y;
pTy[1] = y;
pTy[2] = y - yProp*y;
pTy[3] = y;
pTy[4] = y + yProp*y;
alert(String(pTx[1])+String(pTy[1]));
//Draw diamond
ctx.beginPath();
ctx.moveTo(pTx[0], pTy[0]);
ctx.lineTo(pTx[1],pTy[1]);
ctx.lineTo(pTx[2],pTy[2]);
ctx.lineTo(pTx[3],pTy[3]);
ctx.lineTo(pTx[4],pTy[4]);
ctx.closePath();
ctx.fillstyle() = "#FFFFFF"
ctx.fill();
} else {
// canvas-unsupported code here
log('Fail');
}

You had couple of errors in your script
First:
newArray() should be new Array()
new Array()
^-------- see space
Second:
var pTx = newArray();
pTx[0] = x; // ---> ptx ok
pTy[1] = x + xProp*x; // ---> its pty? why? change all to ptx
pTy[2] = x; // ---> change to ptx
pTy[3] = x - xProp*x; // ---> change to ptx
pTy[4] = x; // ---> change to ptx
It should be
var pTx = new Array();
pTx[0] = x;
pTx[1] = x + xProp*x;
pTx[2] = x;
pTx[3] = x - xProp*x;
pTx[4] = x;
Third
fillStyle is not a method its a property
ctx.fillstyle() = "#FFFFFF"
It should be
ctx.fillstyle = "#FFFFFF"
Demo

Related

How to curve image in differnt shape, just like 'm'

I want to give curve to image just as shirt collar.
Curve image
I have image.Main image
I use below code
<script type="text/javascript">
function allcurve(event){
topcolrcurve(event);
}
function topcolrcurve(event){
var getImagePath = URL.createObjectURL(event.target.files[0]);
console.log(getImagePath)
temp_can1 = document.getElementById('f6258182013');
temp_can1_ctx = temp_can1.getContext('2d');
topcolrrotator(getImagePath, '-100');
}
function topcolrrotator(var2, var3)
{
var mr_rotator_var = document.getElementById('colrtop_can');
var mr_rotator_var_ctx = mr_rotator_var.getContext("2d");
mr_rotator_var.width = mr_rotator_var.width;
var imageObj_rotator3 = new Image();
var hpp='';
imageObj_rotator3.onload = function () {
var pattern_rotator3 = mr_rotator_var_ctx.createPattern(imageObj_rotator3, "repeat");
mr_rotator_var_ctx.fillStyle = pattern_rotator3;
mr_rotator_var_ctx.rect(0, 0, mr_rotator_var.width, mr_rotator_var.height);
mr_rotator_var_ctx.rotate(var3 * Math.PI / 180);
mr_rotator_var_ctx.fill();
hpp = mr_rotator_var.toDataURL('image/png');
rightcufover(hpp);
};
imageObj_rotator3.src = var2;
}
function rightcufover(event)
{
var getImagePath = event;
var ctx = e.getContext("2d");
var img = new Image;
img.onload = slice;
img.src = getImagePath;
function slice() {
var w = e.width = this.width;
var h = e.height = this.height;
var step = Math.PI * 1 / w;
var scale = -100;
for(var x = 0; x < w; x++) {
ctx.drawImage(this,
x, 0, 1, h,
x, Math.sin(step*x)*scale, 1, h);
}
var hp=e.toDataURL('image/png');
$('#collrtop').attr("value", hp);
}
}
Please help how to curve image.
I try it in different way but it not show proper, also I have to maintain quality of image.

Cannot rotate stroke in HTML Canvas

I am trying to create a partial annulus and rotate it.
var c = document.getElementById("c");
var x = c.getContext("2d");
var w = c.width;
var h = c.height;
var cx = w/2;
var cy = h/2;
var sw = 20;
var pi = Math.PI;
var r = Math.min(w, h)/2 - sw/2;
var k = 0;
var i = pi*1/30;
x.lineWidth = sw;
x.lineCap = "butt";
x.beginPath();
x.arc(cx, cy, r, -pi*2, -pi/16);
x.rotate(pi*1/3); // IS NOT TAKING EFFECT
x.stroke();
<canvas id="c" width="100px" height="100px"></canvas>
As you can see, in the last part, before calling stroke(), I perform:
x.rotate(pi*1/3);
However I cannot see the rotation in the final rendering. What am I doing wrong?
When adding paths the current state of the transform will be used at the point it is added. The path will not change afterwards.
So here, simply do the rotate before adding more path data (in this case you also need to use translate to draw the arc from pivot/rotation point).
var c = document.getElementById("c");
var x = c.getContext("2d");
var w = c.width;
var h = c.height;
var cx = w/2;
var cy = h/2;
var sw = 20;
var pi = Math.PI;
var r = Math.min(w, h)/2 - sw/2;
var k = 0;
var i = pi*1/30;
x.lineWidth = sw;
x.lineCap = "butt";
x.beginPath();
x.translate(cx, cy); // update matrix
x.rotate(pi*1/3);
x.arc(0, 0, r, -pi*2, -pi/16); // uses current matrix
x.stroke();
<canvas id="c" width="100px" height="100px"></canvas>

How to divide image in tiles?

I have to achieve the following task:
divides the image into tiles, computes the average color of each tile,
fetches a tile from the server for that color, and composites the
results into a photomosaic of the original image.
What would be the best strategy? the first solution coming to my mind is using canvas.
A simple way to get pixel data and finding the means of tiles. The code will need more checks for images that do not have dimensions that can be divided by the number of tiles.
var image = new Image();
image.src = ??? // the URL if the image is not from your domain you will have to move it to your server first
// wait for image to load
image.onload = function(){
// create a canvas
var canvas = document.createElement("canvas");
//set its size to match the image
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d"); // get the 2d interface
// draw the image on the canvas
ctx.drawImage(this,0,0);
// get the tile size
var tileSizeX = Math.floor(this.width / 10);
var tileSizeY = Math.floor(this.height / 10);
var x,y;
// array to hold tile colours
var tileColours = [];
// for each tile
for(y = 0; y < this.height; y += tileSizeY){
for(x = 0; x < this.width; x += tileSizeX){
// get the pixel data
var imgData = ctx.getImageData(x,y,tileSizeX,tileSizeY);
var r,g,b,ind;
var i = tileSizeY * tileSizeX; // get pixel count
ind = r = g = b = 0;
// for each pixel (rgba 8 bits each)
while(i > 0){
// sum the channels
r += imgData.data[ind++];
g += imgData.data[ind++];
b += imgData.data[ind++];
ind ++;
i --;
}
i = ind /4; // get the count again
// calculate channel means
r /= i;
g /= i;
b /= i;
//store the tile coords and colour
tileColours[tileColours.length] = {
rgb : [r,g,b],
x : x,
y : y,
}
}
// all done now fetch the images for the found tiles.
}
I created a solution for this (I am not getting the tile images from back end)
// first function call to create photomosaic
function photomosaic(image) {
// Dimensions of each tile
var tileWidth = TILE_WIDTH;
var tileHeight = TILE_HEIGHT;
//creating the canvas for photomosaic
var canvas = document.createElement('canvas');
var context = canvas.getContext("2d");
canvas.height = image.height;
canvas.width = image.width;
var imageData = context.getImageData(0, 0, image.width, image.height);
var pixels = imageData.data;
// Number of mosaic tiles
var numTileRows = image.width / tileWidth;
var numTileCols = image.height / tileHeight;
//canvas copy of image
var imageCanvas = document.createElement('canvas');
var imageCanvasContext = canvas.getContext('2d');
imageCanvas.height = image.height;
imageCanvas.width = image.width;
imageCanvasContext.drawImage(image, 0, 0);
//function for finding the average color
function averageColor(row, column) {
var blockSize = 1, // we can set how many pixels to skip
data, width, height,
i = -4,
length,
rgb = {
r: 0,
g: 0,
b: 0
},
count = 0;
try {
data = imageCanvasContext.getImageData(column * TILE_WIDTH, row * TILE_HEIGHT, TILE_HEIGHT, TILE_WIDTH);
} catch (e) {
alert('Not happening this time!');
return rgb;
}
length = data.data.length;
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r / count);
rgb.g = ~~(rgb.g / count);
rgb.b = ~~(rgb.b / count);
return rgb;
}
// Loop through each tile
for (var r = 0; r < numTileRows; r++) {
for (var c = 0; c < numTileCols; c++) {
// Set the pixel values for each tile
var rgb = averageColor(r, c)
var red = rgb.r;
var green = rgb.g;
var blue = rgb.b;
// Loop through each tile pixel
for (var tr = 0; tr < tileHeight; tr++) {
for (var tc = 0; tc < tileWidth; tc++) {
// Calculate the true position of the tile pixel
var trueRow = (r * tileHeight) + tr;
var trueCol = (c * tileWidth) + tc;
// Calculate the position of the current pixel in the array
var pos = (trueRow * (imageData.width * 4)) + (trueCol * 4);
// Assign the colour to each pixel
pixels[pos + 0] = red;
pixels[pos + 1] = green;
pixels[pos + 2] = blue;
pixels[pos + 3] = 255;
};
};
};
};
// Draw image data to the canvas
context.putImageData(imageData, 0, 0);
return canvas;
}
function create() {
var image = document.getElementById('image');
var canvas = photomosaic(image);
document.getElementById("output").appendChild(canvas);
};
DEMO:https://jsfiddle.net/gurinderiitr/sx735L5n/
Try using the JIMP javascript library to read the pixel color and use invert, normalize or similar property for modifying the image.
Have a look on the jimp library
https://github.com/oliver-moran/jimp

What am I doing wrong in the canvas drawing?

I am new to javascript so sorry if my mistake is obvious! I am trying to draw an ellipse using the canonical form equation.
<html>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #000000;">
</canvas>
<script language="javaScript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var HEIGHT = ctx.height;
var WIDTH = ctx.width;
function transform(p){
return [ WIDTH/2 + p[0], HEIGHT/2 - p[1]];
}
var a = 70; //length parallel to x axis
var b = 30; //length parallel to y axis
var h = 150 - WIDTH/2; //when tranformed this gives the pixel 150
var k = -HEIGHT/2 - 100; //when transformed this gives pixel 100
function y(x){
return b*Math.sqrt(1 - Math.pow((x - h)/a, 2)) + k;
}
var dx = a/2/100 ; //each quadrant is broken into 100 segments
var pOld = [h - a/2, k]; //starting point
var pNew = [0,0];
var x1 = 0;
var x2 = 0;
var y1 = 0;
var y2 = 0;
var temp = [0,0];
for (var i = 0; i < 100; ++i){
pNew[0] = pOld[0] + dx;
pNew[1] = y(pNew[0]);
temp = transform(pOld);
x1 = temp[0]; y1 = temp[1];
temp = transform(pNew);
x2 = temp[0]; y2 = temp[1];
ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); //x1, y1 -> x2, y2
ctx.moveTo(x1, -y1); ctx.lineTo(x2, -y2); //x1,-y1 -> x2,-y2
ctx.moveTo(-x1, y1); ctx.lineTo(-x2, y2); //-x1,y1 -> -x2, y2
ctx.moveTo(-x1, -y1); ctx.lineTo(-x2, -y2); //-x1,-y1 -> -x2,-y2
pOld = pNew;
}
ctx.lineWidth = 2;
ctx.strokeStyle = "#232323";
ctx.stroke();
</script>
</body>
</html>
You values are NaN (Not-a-Number). Change these lines:
var HEIGHT = ctx.height;
var WIDTH = ctx.width;
to
var HEIGHT = c.height;
var WIDTH = c.width;
and you get proper Numbers. However, your y value is outside the canvas area - you will see this if you console.log the values. There seem to be some issues with the math in general which I don't address here, but in relation to canvas you should be one step further.

Overlap/hit test in javascript

Im trying to get a hit test/overlap test to work in the below code which creates 200 circles in a random position on a canvas. I am trying to store the positions of the circles in an array and then checking that array each time another circle is created in the for loop, if the randomly created x and y is too close to a already created circle it should keep getting a new random x and y until it isnt too close to an already created circle.
I just cant get it too work in the while loop.
Any help please...
Thanks
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", canvasDraw);
function canvasDraw () {
var c = document.getElementById("canvas");
var w = window.innerWidth;
var h = window.innerHeight;
c.width = w;
c.height = h;
var ctx = c.getContext("2d");
ctx.clearRect(0,0,c.width, c.height);
var abc = 0;
var colours = new Array ("rgb(0,100,0)", "rgb(51,102,255)");
var positions = new Array();
function hitTest(x, y) {
for(var p in positions) {
pp = p.split(",");
pp[0] = parseInt(pp[0]);
pp[1] = parseInt(pp[1]);
if(((x > (pp[0] - 24)) && (x < (pp[0] + 24))) && ((y > (pp[1] - 24)) && (y < (pp[1] + 24)))) {
return true;
}
}
return false;
}
//Loop 200 times for 200 circles
for (i=0; i<200; i++) {
var x = Math.floor(Math.random()*c.width);
var y = Math.floor(Math.random()*c.height);
while(hitTest(x, y) == true){
var x = Math.floor(Math.random()*c.width);
var y = Math.floor(Math.random()*c.height);
}
var pos = x.toString() + "," + y.toString();
positions.push(pos);
var radius = 10;
var r = radius.toString();
var b = colours[Math.floor(Math.random()*colours.length)];
circle(ctx,x,y, radius, b);
}
}
function circle (ctx, x, y, radius, b) {
ctx.fillStyle = b;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
</script>
Some things before beginning:
Don't create arrays with new Array(), unless you specify the initial length. Use [];
Don't iterate through arrays using for...in: use a standard for with a counter. This is more a good practice;
Converting numbers into strings and converting back to numbers is useless and expensive. Use a small array to store both values;
Don't use "magic numbers", i.e. number with a precise value but hard to recognize immediately. Use named "constants" or put a comment near each of them telling what they mean, for future maintenance.
Ok, let's see the code.
if(((x > (pp[0] - 24)) && (x < (pp[0] + 24))) && ((y > (pp[1] - 24)) && (y < (pp[1] + 24))))
Honestly, what is this? I'd call it a cranky and obscure snippet. Recall what you've learnt at school:
var dx = pp[0] - x, dy = pp[1] - y;
if (dx * dx + dy * dy < 400) return true;
Isn't it much clearer?
Let's see the whole function:
function canvasDraw () {
var c = document.getElementById("canvas");
var w = window.innerWidth;
var h = window.innerHeight;
c.width = w;
c.height = h;
var ctx = c.getContext("2d");
ctx.clearRect(0,0,c.width, c.height);
// Lolwut?
// var abc = 0;
var colours = ["rgb(0,100,0)", "rgb(51,102,255)"];
var positions = [];
function hitTest(x, y) {
for (var j = 0; j < positions.length; j++) {
var pp = positions[j];
var dx = pp[0] - x, dy = pp[1] - y;
if (dx * dx + dy * dy < 400) return true;
}
return false;
}
// You declare the radius once and for all
var radius = 10;
// Declare the local scoped variables. You forgot i
var x, y, i;
for (i=0; i<200; i++) {
// How about a do...while instead of a while?
do {
var x = Math.floor(Math.random()*c.width);
var y = Math.floor(Math.random()*c.height);
// Testing with === is faster, always do it if you know the type
// I'll let it here, but if the type is boolean, you can avoid testing
// at all, as in while (hitTest(x, y));
} while (hitTest(x, y) === true);
positions.push([x, y]);
// This instruction is useless
// var r = radius.toString();
var b = colours[Math.floor(Math.random()*colours.length)];
circle(ctx,x,y, radius, b);
}
}
BEWARE, though, that depending on your canvas size, there could be no more room for another circle, so it could end in an infinite loop. Try to put 200 circles with a radius of 10 inside a 40x40 box...
There should be another test to do, and that could be complicated.

Categories

Resources