Multiple html canvas element with random graphics on same page - javascript

Trying to create multiple canvas element on a single html page and then draw different graphics on each of them . But the issue is , the same graphics is drawn on all of them without any randomization
canvas_container_div = document.getElementById('canvas_container_div');
let animation_frame_id;
let canvas_array = [];
let context_array = [];
let number_of_canvas = 5;
//creating canvas and storing it in an array
for(var i = 0;i < number_of_canvas ; i++){
var canvas1 = document.createElement('canvas');
canvas1.style.width = '200px';
canvas1.style.height = '200px';
canvas1.style.margin = '10px';
canvas1.style.border = '1px solid white';
canvas_array.push(canvas1);
}
//displaying all canvas inside the div element
for(var i = 0;i < canvas_array.length ; i++){
canvas_container_div.appendChild(canvas_array[i]);
}
//getting all the contex for all the canvas
for(var i = 0;i < canvas_array.length ; i++){
context_array.push(canvas_array[i].getContext('2d'));
}
//random values generating
let hue = Math.random()*360;
//or other radom parameters
//updating each graphics
function update(ctx){
ctx.fillStyle = 'hsl('+hue+',100%,50%)';
}
function render(){
//getting all the context
for(var i = 0;i < context_array.length ; i++){
//clearing bg for perticular canvas
context_array[i].clearRect(0,0,canvas_array[i].width,canvas_array[i].height);
//passing perticular canvas context to update method
update(context_array[i]);
//drawing with pertucular context
context_array[i].beginPath();
context_array[i].arc(canvas_array[i].width/2,canvas_array[i].height/2,40,0,Math.PI *2);
context_array[i].closePath();
context_array[i].fill();
}
animation_frame_id = requestAnimationFrame(render);
}
render();
Wanted to have different color for all the circle drawn on different canvas , but all the circles are of same color . cannot randomize

You are defining your hue outside of your renders for loop, so each time it runs the loop and calls on the hue, it is getting the same color for the fill style. You could create a function that randomizes the hue inside a for loop to to create an array of colors that is the same length as your canvas array.
Then in your for loop within the render function call on the array and its index to make each individual circle a different color fill style.
NOTE: This only randomizes the colors, it does not check if a color already exists, so you may want additional code to check if a number is already in the array before pushing the value into the array. Furthermore, you will notice some hues randomize within a certain number close enough to each other that they actually look like they are the same, you could also include code within the setHue() function that checks to see if the the numbers are within a certain restraint of each other, this would likely be a .include() or even a conditional that checks the difference between the hue array and the current value within the loop.
let hue = [];
function setHue() {
for (let h = 0; h < context_array.length; h++) {
hue.push(Math.trunc(Math.random() * 360));
}
}
setHue();
canvas_container_div = document.getElementById('canvas_container_div');
let animation_frame_id;
let canvas_array = [];
let context_array = [];
let number_of_canvas = 5;
//creating canvas and storing it in an array
for (var i = 0; i < number_of_canvas; i++) {
var canvas1 = document.createElement('canvas');
canvas1.style.width = '200px';
canvas1.style.height = '200px';
canvas1.style.margin = '10px';
canvas1.style.border = '1px solid white';
canvas_array.push(canvas1);
}
//displaying all canvas inside the div element
for (var i = 0; i < canvas_array.length; i++) {
canvas_container_div.appendChild(canvas_array[i]);
}
//getting all the contex for all the canvas
for (var i = 0; i < canvas_array.length; i++) {
context_array.push(canvas_array[i].getContext('2d'));
}
//Randomize your hue value and make an array to hold the value
//Then in your for loop within the render function call on the
//array and its index to make each individual circle a different color fill style
let hue = [];
function setHue() {
for (let h = 0; h < context_array.length; h++) {
let color = Math.trunc(Math.random() * 360);
hue.push(color);
}
console.log(hue);
}
setHue();
function render() {
//getting all the context
for (var i = 0; i < context_array.length; i++) {
//clearing bg for perticular canvas
context_array[i].clearRect(0, 0, canvas_array[i].width, canvas_array[i].height);
//drawing with particular context
context_array[i].beginPath();
context_array[i].arc(canvas_array[i].width / 2, canvas_array[i].height / 2, 40, 0, Math.PI * 2);
context_array[i].closePath();
context_array[i].fill();
context_array[i].fillStyle = 'hsl(' + hue[i] + ',100%,50%)';
}
animation_frame_id = requestAnimationFrame(render);
}
render();
<div id="canvas_container_div"></div>

Related

Can I not use an object in an object for drawImage()?

I can't seem to figure out why my code doesn't work. What I'm essentially trying to do is generate a 10x10 tile based map using arrays.
The idea is to create an object called Box with an 'x' and 'y' axis property and also an image object within the box. Then, each position in the 2d array is populated with a box object.
I then want to draw all these arrays out on a canvas. Each tile(or array element) is a 64x64 box.
const ROW = 10;
const COLS = 11;
const SIZE = 64;
var canvas = document.getElementById("canvas");
var surface = canvas.getContext("2d");
//creating tile
function box() {
this.xaxis = 56;
this.yaxis = 0;
this.img = new Image();
this.img.src = "box_image.png";
}
//creating map
var map =[];
function setMap() {
for (var i = 0; i < ROW; i++) {
for (var o = 0; o < COLS; o++) {
map[i][o] = new box();
}
}
}
//rendering map
function render() {
for (var i = 0; i < map.length; i++) {
for (var x = 0; x < map.length; x++) {
var tile = map[i][x];
tile.xaxis *= i;
tile.yaxis *= x;
surface.drawImage(tile.img, tile.xaxis, tile.yaxis, 64, 64);
}
}
}
setTimeout(render, 10);
Adding a few elements you forgot, here's how I would do it.
Fiddle
HTML
<canvas id="canvas" width="1000" height="1000"></canvas>
<!-- set canvas size -->
JS
const ROW = 10;
const COLS = 11;
const SIZE = 64;
var canvas = document.getElementById("canvas");
var surface = canvas.getContext("2d");
//creating tile
function box() {
this.xaxis = 56;
this.yaxis = 0;
this.src = "https://cdn4.iconfinder.com/data/icons/video-game-adicts/1024/videogame_icons-01-128.png"; //save path to image
}
//creating map
var map =[];
function setMap() {
for (var i = 0; i < ROW; i++) {
var arr = []; //make new row
map.push(arr); //push new row
for (var o = 0; o < COLS; o++) {
map[i].push(new box()); //make and push new column element in current row
}
}
}
//rendering map
function render() {
for (var i = 0; i < ROW; i++) { //For each row
for (var x = 0; x < COLS; x++) { //And each column in it
var tile = map[i][x];
tile.xaxis *= i;
tile.yaxis += (x*SIZE); //increment y value
var img = new Image();
img.onload = (function(x,y) { //draw when image is loaded
return function() {
surface.drawImage(this, x, y, 64, 64);
}
})(tile.xaxis, tile.yaxis);
img.src = tile.src;
}
}
}
setMap(); //create the grid
render(); //render the grid
There are a number of errors in your code.
First you are loading the same image 110 times. Load it once and that will save a lot of memory and time.
You create a single dimetioned array map
map = [];
Then attempt to access to as a two dim map. map[i][o] that will not work. You need to create a new array for each row.
You create the function to populate the map setMap() but you never call the function.
The Boxes you create have the yaxis value set to 0. When you call render and multiply it by the column index the result will be zero, so you will only see one column of images. You need to set the yaxis value to some value (64)
Below is your code fixed up with some comments. I left the zero yaxis value as maybe that is what you wanted. The image is created only once and the onload event is used to call render When setMap is called I add a new array for each row. I call setMap at the bottom but can be called anytime after you declare and define var map = [];
const ROW = 10;
const COLS = 11;
const SIZE = 64;
const canvas = document.getElementById("canvas");
const surface = canvas.getContext("2d");
const image = new Image();
image.src = "box_image.png";
// onload will not fire until all the immediate code has finished running
image.onload = function(){render()}; // call render when the image has loaded
//creating tile
function Box() { // any function you call with new should start with a capital
this.xaxis = 56;
this.yaxis = 0; // should this not be something other than zero
this.img = image;
}
//creating map
const map =[];
function setMap() {
for (var i = 0; i < ROW; i++) {
var row = []; // new array for this row
map[i] = row;
for (var o = 0; o < COLS; o++) {
row[o] = new box();
}
}
}
//rendering map
function render() {
for (var i = 0; i < map.length; i++) {
for (var x = 0; x < map[i].length; x++) { // you had map.length you needed the array for row i which is map[i]
var tile = map[i][x];
tile.xaxis *= i;
tile.yaxis *= x; // Note you have zero for yaxis?? 0 times anything is zero
surface.drawImage(tile.img, tile.xaxis, tile.yaxis, 64, 64);
}
}
}
setMap(); // create the map

How to set rectangles as objects to array in JS?

I am a beginer. I want to create a pixel art site. For this I try to develope my javascript code. Now I am on the way to simplify the code by setting the different rectangles using var as object and array to avoid to type milles of lines. Than I think to create at the second part an array constructor with defining coords(other x, other y) for every single rectangle in 2D array.
At the moment I don't relise why the first part of the code is not working. Can you please suggest your mind? Thanks a lot in advance.
Here is my code (link on JS Bin):
var canvas;
var ctx;
var x = 0;
var y = 0;
var w = 10; // Width=10px
var h = w; // Heigth=10px
function init() {
canvas = document.querySelector('#myCanvas');
ctx = canvas.getContext('2d');
draw();
}
// Create a rect by path method for restoring the buffer
var rect;
function draw(){
ctx.beginPath();
ctx.rect(x,y,w,h);
}
var c = ['#66757F', '#F7F7F7', '#CCD6DD']; // Setting a color palette as an array
for (var i=0; i<c.length; i++){
c[i]=ctx.fillStyle();
}
// Define colored rectangles as the Objects
var r1 = {rect;[0]}
var r2 = {rect;[1]}
var r3 = {rect;[2]}
ctx.fill();
// Setting three rectangle by diagonal
var r=[r1,r2,r3];// Array of setted rectangles
function draw(){
for (var j=0; j<r.length; j++){
r[j]=ctx.moveTo(x+w*j,y+h*j);
}
}
for (var j=0; j<r.length; i++){
r[j]=ctx.moveTo(x+w*j,y+h*j);
}
You typed 'i++' when using the letter 'j'.
Not sure whether this solves the problem.
Why do you use Math.abs in
var w = Math.abs(-10); // Width=10px
Isn't it easier to set 'var w' to 10 ?
var w = 10;
Is what you're looking for how to create classes and make objects from that class?
If so this is how you would create a class and make objects.
//This will hold all of your objects.
var listOfObjects = [];
//This is a class. You can create objects with it.
function myClass() {
//location
this.X = 0;
this.Y = 0;
//size
this.width = 5;
this.height = 5;
}
function CreateNewObject() {
//This will create and add an object of myClass to your array.
//Now you can loop through the array and modify the values as you wish.
listOfObjects.push(new myClass());
}

Gradient fill empty in for loop

I'm drawing buttons on createjs canvas that have gradient fill and stroke. The number of buttons are drawn inside a for loop. Each section, as you will see in the fiddle, is drawn separately via function. but only the first function run draws the correct fill. The subsequent calls only draws the gradient stroke Jsfiddle
for (i = 0; i < db.length; i++) {
var btn = db[i];
var sdb = btn.split("_");
var blabel = sdb[0];
var battrib = sdb[1];
var bval = sdb[2];
var sid = sdb[3];
var tick = sdb[4];
var cptn = sdb[5];
var imageType = sdb[6];
var buttonSize = 90 + 10;
var bttn = new c.Shape();
bttn.graphics.beginLinearGradientFill([grad1, grad2], [.2, 1], 0, 0,0,50 ).setStrokeStyle(3).beginLinearGradientStroke([grad2, grad1], [.2, 1], 0, 0,0,50 ).drawRoundRect(x, y, 85, 35,5);
var label = new c.Text(blabel);
label.font = font;
label.color = '#000';
label.x = x+8;
label.y = y+6;
m1.addChild(bttn, label);
x+= buttonSize;
}s.update();
It seems to be working to me. Is it perhaps that you forgot to offset your buttons, so you're only seeing the first one? bttn.y = i*40
https://jsfiddle.net/gskinner/wqu4nzdq/12/

javascript - iterating over bidimensional arrays

I am trying to write a javascript program that renders an 8x8 grid of dirt tiles on an HTML5 canvas. However, when I run this code it throws up error messages when running the draw_terrain() function and it appears to be a problem with the blockArray.length component. Can someone explain to me how to fix this problem? Thanks in advance.
//Define initial canvas variables and images
var canvas;
var ctx;
var WIDTH = 800;
var HEIGHT = 800;
var dirt = new Image();
dirt.src = 'dirt.png';
//Function called to initialise canvas variables and run draw on interval
function init(){
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
return setInterval(draw, 15);
}
//Function that generates an 8x8 Array called blockArray
function gen_terrain(){
var blockArray = new Array(8);
for(var i=0; i<blockArray.length; i++) {
blockArray[i] = new Array(8);
for(var j=0; j<blockArray[i].length; j++){
blockArray[i][j] = 0;
};
};
}
//Function that returns a random number between a min and max
function randomRange (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function draw_terrain(){
for(var i=0; i<blockArray.length; i++) {
for(var j=0; j<blockArray[i].length; j++){
ctx.drawImage(dirt,(n-1)*32,(j-1)*32);
};
};
}
function draw(){
draw_terrain();
}
gen_terrain();
init();
Your problem, as other people have explained is that the variable you are using the build the array will not exist by the time the draw occurs. Just place your array declaration outside of the function and your issue will go away.
See comment below:
function init(){
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
return setInterval(draw, 15);
}
//Function that generates an 8x8 Array called blockArray
var blockArray = []; // <== has to be global (outside function).
function gen_terrain(){
// Not here -> var blockArray = [];
for(var i=8; i--;) {
blockArray[i] = [0,0,0,0,0,0,0,0];
};
}
Example

How to draw a simple 2D grid (non interactive) in PaperJS?

I have an interactive application mockup made with PaperJS but it still lacks a small feature. I need to draw a 2D grid (you know... that uniform mesh of lines that repeat endlessly over a surface), it will be used as guides for user interactions when dragging things over the screen (but the grid itself can be completely static).
I just don't know how to implement it in PaperJS. It can't be just a background image since it will be presented in different scales, also I wanted it to be rendered very fast since it will always be visible.
The type of grid I would like to draw is a 2D mesh centered grid, like in the example (a) of this picture:
Any enlightenment is welcome.
If all you want is lines:
var drawGridLines = function(num_rectangles_wide, num_rectangles_tall, boundingRect) {
var width_per_rectangle = boundingRect.width / num_rectangles_wide;
var height_per_rectangle = boundingRect.height / num_rectangles_tall;
for (var i = 0; i <= num_rectangles_wide; i++) {
var xPos = boundingRect.left + i * width_per_rectangle;
var topPoint = new paper.Point(xPos, boundingRect.top);
var bottomPoint = new paper.Point(xPos, boundingRect.bottom);
var aLine = new paper.Path.Line(topPoint, bottomPoint);
aLine.strokeColor = 'black';
}
for (var i = 0; i <= num_rectangles_tall; i++) {
var yPos = boundingRect.top + i * height_per_rectangle;
var leftPoint = new paper.Point(boundingRect.left, yPos);
var rightPoint = new paper.Point(boundingRect.right, yPos);
var aLine = new paper.Path.Line(leftPoint, rightPoint);
aLine.strokeColor = 'black';
}
}
drawGridLines(4, 4, paper.view.bounds);
If you want each rectangle to be a separate Path to hitTest for the individual rectangles:
var drawGridRects = function(num_rectangles_wide, num_rectangles_tall, boundingRect) {
var width_per_rectangle = boundingRect.width / num_rectangles_wide;
var height_per_rectangle = boundingRect.height / num_rectangles_tall;
for (var i = 0; i < num_rectangles_wide; i++) {
for (var j = 0; j < num_rectangles_tall; j++) {
var aRect = new paper.Path.Rectangle(boundingRect.left + i * width_per_rectangle, boundingRect.top + j * height_per_rectangle, width_per_rectangle, height_per_rectangle);
aRect.strokeColor = 'white';
aRect.fillColor = 'black';
}
}
}
drawGridRects(4, 4, paper.view.bounds);

Categories