I'm having a little trouble with randomly positioning a bunch of random boxes throughout a page.
The goal is to have a randomly amount of boxes show up in random positions and the boxes are to be random colors on a page. The boxes should also be overlapping, making them truly in random positions.
Thus far all I have is one randomly colored box on the page, clearly not randomly positioned. I'm suck of where to go from here with the positioning and creating a bunch of random boxes...
Please note JQuery cannot be used.
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ramdom Boxes</title>
<script src="A2Q1.js"></script>
</head>
<body>
</body>
</html>
Javascript:
window.onload = init;
function init() {
//when page is loaded create a bunch of boxes randomly throughout the page
//get the body element of the document
var body = document.getElementsByTagName("body")[0];
//create the canvas tag
var canvas = document.createElement("canvas");
canvas.height = 100;
canvas.width = 100;
var context = canvas.getContext("2d");
//create the box and append onto the canvas
var colour = '#'+ Math.round(0xffffff * Math.random()).toString(16);
context.fillStyle = colour;
context.fillRect(25,25,50,50);
//append the canvas onto the body
body.appendChild(canvas);
}
It would be better to resize the canvas as much as window size. In order to draw a bunch of rectangles, use for loop to execute draw rectangle code repeatedly. Set each rectangle's position in window width and height (Math.random() * window.innerWidth, Math.random() * window.innerHeight).
Here is my sample code.
function init() {
var body = document.getElementsByTagName("body")[0];
var canvas = document.createElement("canvas");
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
var context = canvas.getContext("2d");
// Opacity makes a good appearance when objects are overlapped
context.globalAlpha=0.7;
// Repeat to draw a rectangle 100 times
for(var i=0;i<100;i++){
var color = '#'+ Math.round(0xffffff * Math.random()).toString(16);
context.fillStyle = color;
//Each rectangle is at (0 ~ width of window, 0 ~ height of window)
//Each rectangle's size is (20 ~ 100, 20 ~ 100)
context.fillRect(Math.random()*window.innerWidth, Math.random()*window.innerHeight, Math.random()*80+20, Math.random()*80+20);
}
body.appendChild(canvas);
}
window.onload = init;
For generating the random color you can refer this post
In order to get the x and y random values with respect to the width and height of the entire screen try this.
var maxWidth = 1000;
var maxHeight = 1000;
var randomX = Math.max(0, Math.min((maxWidth - boxWidth), Math.random() * maxWidth));
var randomY = Math.max(0, Math.min((maxHeight - boxHeight), Math.random() * maxHeight));
Set the position for the canvas like this.
box.style.position = "absolute";
box.style.left = randomX;
box.style.top = randomX;
create a table in your page and put that random box randomly to a cell.
for example
<table>
<!--many cell-->
</table>
then you may put your box randomly to a table's cell.
Related
Introduction
I'm trying to deal with blurry visuals on my canvas animation. The blurriness is especially prevalent on mobile-devices, retina and high-dpi (dots-per-inch) screens.
I'm looking for a way to ensure the pixels that are drawn using the canvas look their best on low-dpi screens and high-dpi screens. As a solution to this problem I red multiple articles about canvas-down-scaling and followed this tutorial:
https://www.kirupa.com/canvas/canvas_high_dpi_retina.htm
Integrating down-scaling in the project
The project in which I want to implement down-scaling can be found below and consists of a few important features:
There is a (big) main canvas. (Performance optimization)
There are multiple (pre-rendered) smaller canvasses that are used to draw and load a image into. (Performance optimization)
The canvas is animated. (In the code snippet, there is no visible animation but the animation function is intergrated.)
Question
What im trying to achieve: The problem I'm facing seems quite simple. When the website (with the canvas) is opened on a mobile device (eg. an Iphone, with more pixels per inch then a regular desktop). The images appear more blurry. What I'm actually trying to achieve is to remove this blurriness from the images. I red this and it stated that blurriness can be removed by downsampling. I tried to incorporate this technique in the code provided, but it did not work completely. The images just became larger and I was unable to scale the images back to the original size. snippet it is not implemented correctly, the output is still blurry. What did I do wrong and how am I able to fix this issue?
Explanation of the code snippet
The variable devicePixelRatio is set to 2 to simulate a high-dpi phone screen, low-dpi screens have a devicePixelRatio of 1.
Multiple pre-rendered canvasses generated is the function spawn is the snippet there are 5 different canvasses, but on the production environment there are 10's.
If there are any pieces of information missing or questions about this post, please let me know. Thanks a lot!
Code Snippet
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d' );
var circles = [];
//Simulate Retina screen = 2, Normal screen = 1
let devicePixelRatio = 2
function mainCanvasPixelRatio() {
// get current size of the canvas
let rect = canvas.getBoundingClientRect();
// increase the actual size of our canvas
canvas.width = rect.width * devicePixelRatio;
canvas.height = rect.height * devicePixelRatio;
// ensure all drawing operations are scaled
c.scale(devicePixelRatio, devicePixelRatio);
// scale everything down using CSS
canvas.style.width = rect.width + 'px';
canvas.style.height = rect.height + 'px';
}
// Initial Spawn
function spawn() {
for (let i = 0; i < 2; i++) {
//Set Radius
let radius = parseInt(i*30);
//Give position
let x = Math.round((canvas.width/devicePixelRatio) / 2);
let y = Math.round((canvas.height /devicePixelRatio) / 2);
//Begin Prerender canvas
let PreRenderCanvas = document.createElement('canvas');
const tmp = PreRenderCanvas.getContext("2d");
//Set PreRenderCanvas width and height
let PreRenderCanvasWidth = ((radius*2)*1.5)+1;
let PreRenderCanvasHeight = ((radius*2)*1.5)+1;
//Increase the actual size of PreRenderCanvas
PreRenderCanvas.width = PreRenderCanvasWidth * devicePixelRatio;
PreRenderCanvas.height = PreRenderCanvasHeight * devicePixelRatio;
//Scale PreRenderCanvas down using CSS
PreRenderCanvas.style.width = PreRenderCanvasWidth + 'px';
PreRenderCanvas.style.height = PreRenderCanvasHeight + 'px';
//Ensure PreRenderCanvas drawing operations are scaled
tmp.scale(devicePixelRatio, devicePixelRatio);
//Init image
const image= new Image();
//Get center of PreRenderCanvas
let m_canvasCenterX = (PreRenderCanvas.width/devicePixelRatio) * .5;
let m_canvasCenterY = (PreRenderCanvas.height/devicePixelRatio) * .5;
//Draw red circle on PreRenderCanvas
tmp.strokeStyle = "red";
tmp.beginPath();
tmp.arc((m_canvasCenterX), (m_canvasCenterY), ((PreRenderCanvas.width/devicePixelRatio)/3) , 0, 2 * Math.PI);
tmp.lineWidth = 2;
tmp.stroke();
tmp.restore();
tmp.closePath()
//Set Image
image .src= "https://play-lh.googleusercontent.com/IeNJWoKYx1waOhfWF6TiuSiWBLfqLb18lmZYXSgsH1fvb8v1IYiZr5aYWe0Gxu-pVZX3"
//Get padding
let paddingX = (PreRenderCanvas.width/devicePixelRatio)/5;
let paddingY = (PreRenderCanvas.height/devicePixelRatio)/5;
//Load image
image.onload = function () {
tmp.beginPath()
tmp.drawImage(image, paddingX,paddingY, (PreRenderCanvas.width/devicePixelRatio)-(paddingX*2),(PreRenderCanvas.height/devicePixelRatio)-(paddingY*2));
tmp.closePath()
}
let circle = new Circle(x, y, c ,PreRenderCanvas);
circles.push(circle)
}
}
// Circle parameters
function Circle(x, y, c ,m_canvas) {
this.x = x;
this.y = y;
this.c = c;
this.m_canvas = m_canvas;
}
//Draw circle on canvas
Circle.prototype = {
//Draw circle on canvas
draw: function () {
this.c.drawImage( this.m_canvas, (this.x - (this.m_canvas.width)/2), (this.y - this.m_canvas.height/2));
}
};
// Animate
function animate() {
//Clear canvas each time
c.clearRect(0, 0, (canvas.width /devicePixelRatio), (canvas.height /devicePixelRatio));
//Draw in reverse for info overlap
circles.slice().reverse().forEach(function( circle ) {
circle.draw();
});
requestAnimationFrame(animate);
}
mainCanvasPixelRatio()
spawn()
animate()
#mainCanvas {
background:blue;
}
<canvas id="mainCanvas"></canvas>
<br>
<!DOCTYPE html>
<html>
<body>
<p>Image to use:</p>
<img id="scream" width="220" height="277"
src="pic_the_scream.jpg" alt="The Scream">
<p>Canvas:</p>
<canvas id="myCanvas" width="240" height="297"
style="border:1px solid #d3d3d3;">
</canvas>
<script>
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("scream");
ctx.drawImage(img, 10, 10);
};
</script>
</body>
I am trying to animate using a sprite sheet and use it in my website, however I am knew to animation and I am having some trouble fixing it, currently nothing shows up on my webpage when I use this. I am using a sprite sheet which is called Speech.png, is 18176 x 256 and each frame is 256x256. Here is my code so far.
<script language="javascript">
// screen size variables
var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight;
var canvas = document.createElement('canvas');
var c = canvas.getContext('2d');
canvas.width = SCREEN_WIDTH;
canvas.height = SCREEN_HEIGHT;
var xpos=0,
ypos=0,
index=0,
numFrames = 70,
frameSize= 255;
// Add our drawing canvas
document.body.appendChild(canvas);
//load the image
image = new Image();
image.src = "Speech.png";
image.onload = function() {
//we're ready for the loop
setInterval(loop, 1000 / 30);
}
function loop() {
//clear the canvas!
c.clearRect(0,0, SCREEN_HEIGHT,SCREEN_WIDTH);
/*our big long list of arguments below equates to:
1: our image source
2 - 5: the rectangle in the source image of what we want to draw
6 - 9: the rectangle of our canvas that we are drawing into
the area of the source image we are drawing from will change each time loop() is called.
the rectangle of our canvas that we are drawing into however, will not.
tricky!
*/
c.drawImage(image,xpos,ypos,frameSize,frameSize,0,0,frameSize, frameSize);
//each time around we add the frame size to our xpos, moving along the source image
xpos += frameSize;
//increase the index so we know which frame of our animation we are currently on
index += 1;
//if our index is higher than our total number of frames, we're at the end and better start over
if (index >= numFrames) {
xpos = 0;
ypos = 0;
index = 0;
//if we've gotten to the limit of our source image's width, we need to move down one row of frames
} else if (xpos + frameSize > image.width){
xpos =0;
ypos += frameSize;
}
}
</script>
I have this idea, in which you can only see blackness on the site, but when you hover on it with your mouse it shows a radial gradient white circle that reveals the menu items beneath it, such as "contact", "info", and "products". And when you click on "products" all the items on the page appears, but still they are hidden under the blackness and only show when you hover on it. If you click on any of the products, you can go to product page through the a tag link.
So I get the both parts - 1) reveal things with gradient circle, and 2) products shown after clicking on "products" - to work, but the canvas part with the gradient just get stuck when the products appear. That's probably because I tried to do it in a hacky way by separating these two interactions, as follows:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="./assets/stylesheet/normalize.css">
<link rel="stylesheet" type="text/css" href="./assets/stylesheet/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
</head>
<body>
<div id="menu">
<div class="menu-item" id="products"><a>Products</a></div>
<div class="menu-item" id="contact">News</div>
</div>
<script>
// create a full screen canvas
var canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.left = "0px";
canvas.style.top = "0px";
canvas.style.zIndex = 10;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
// var to hold context
var ctx;
// load an image
var image = new Image();
image.src = "./assets/images/white.jpg";
// add resize event
var resize = function(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx = canvas.getContext("2d");
}
// add mouse event. Because it is full screen no need to bother with offsets
var mouse = function(event){
posX = event.clientX;
posY = event.clientY;
}
// incase the canvas size is changed
window.addEventListener("resize",resize);
// listen to the mouse move
canvas.addEventListener("mousemove",mouse);
// Call resize as that gets our context
resize();
// define the gradient
var cirRadius = 300;
var posX = 100; // this will be set by the mouse
var posY = 100;
var RGB = [11,11,11] ; // black any values from 0 to 255
// var alphas = [0,0,0.2,0.5,0.9,0.95,1]; // zero is transparent one is not
var alphas = [0,0,0.1,0.5,1];
// the update function
var update = function(){
if(ctx){ // make sure all is in order..
if(image.complete){ // draw the image when it is ready
ctx.drawImage(image,0,0,canvas.width,canvas.height)
}else{ // while waiting for image clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
}
// create gradient
var grad = ctx.createRadialGradient(posX,posY,0,posX,posY,cirRadius);
// add colour stops
var len = alphas.length-1;
alphas.forEach((a,i) => {
grad.addColorStop(i/len,`rgba(${RGB[0]},${RGB[1]},${RGB[2]},${a})`);
});
// set fill style to gradient
ctx.fillStyle = grad;
// render that gradient
ctx.fillRect(0,0,canvas.width,canvas.height);
}
requestAnimationFrame(update); // keep doing it till cows come home.
}
// start it all happening;
requestAnimationFrame(update);
</script>
<script>
$("#products").click(function(){
$("#products").remove();
var diagram = document.createElement("div");
diagram.style.position = "absolute";
diagram.style.left = "0px";
diagram.style.top = "0px"
diagram.style.zIndex = 100;
diagram.style.width = window.innerWidth + "px";
diagram.style.height = window.innerHeight + "px";
document.body.appendChild(diagram);
var products = [{
titleShort: "Black",
mainImage: "N/A",
link: "./black.html"
}, {
titleShort: "White",
mainImage: "N/A",
link: "./white.html"
}, {
titleShort: "Red",
mainImage: "N/A",
link: "./red.html"
}, {
titleShort: "Blue",
mainImage: "N/A",
link: "./blue.html"
}]
for (var i = 0; i < products.length; i++) {
var product = document.createElement("div");
diagram.appendChild(product);
productstyle.position = "absolute";
product.style.width = "120px";
product.style.height = "50px";
product.style.top = i * 100 + "px";
product.style.left = i * 100 + "px";
product.style.textAlign = "center";
var circle = document.createElement("a");
circle.style.width = "15px";
circle.style.height = "15px";
circle.style.borderRadius = "50%";
circle.style.backgroundColor = "black";
circle.style.marginLeft = "auto";
circle.style.marginRight = "auto";
circle.href = products[i].link;
product.appendChild(circle);
}
});
</script>
</body>
</html>
Note: all the products are just represented by the dots/circles for sake of convenience.
It's probably best if I merge two parts into one canvas. For example, right now we have that white image as the background for the canvas, if in some ways we can update the image with the products? But I'm very new to canvas and therefore not sure how to do this. Any other suggestions welcome as well.
You could use a div (a) with display none, border radius 50%, an insanely high value for border (solid, black), position fixed and a high z-index. Then use a second div (b) with width 100%, height 100%, background black and also position fixed and a high z-index.
Your "hotspots" have a mouseon handler on it on which you set the position of "a" to the position of the hotspot, set it to display block and set "b" to display none.
A mouseout event then does everything backwards.
Now most people would mislike the idea of a imense border, but hey: it's not like it takes more traffic than any other border and it should be way more performant than to use canvases aswell as way less code.
P.s.: sry i can't provide any code samples since I'm on mobile. This also explains the typos. If you like the idea I (or someone in the comments) can write you a quick fiddle. Also if you are using a js library (like jQuery for example) we can consider this in the snippets.
Edit 1: sorry, I didn't noticed your code already contained the jQuery include. This should make the js part just a few lines...
Also with a little extra code you can have transitions, gradients,.... any fancyness you like
I'm filling canvas with some dynamic texts in ArrayList. And I set the height as length of ArrayList like ArrayList.length * 20 or something like that.
HTML:
<canvas id="myCanvas" width="272px" style="border: 1px solid black"></canvas>
JS :
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var myheight = 10;
for(var i = 0; mylist.length > i; i++){
context.fillText("my text", 10, myheight);
myheight += 10;
}
loop works fine, texts are filled.. and I'm trying to calculate the canvas.height after the loop.
When I set canvas.height = myheight and all filled texts are gone.. canvas gone blank.
How can I set height after canvas filled by texts dynamically?
Help me..
Thank you.. And sorry for bad English..
Resizing window or canvas using canvas.height = myheight clears the canvas
you need to sava the content of canvas and redraw it again on the resized canvas
If you want to save the content of the canvas and redraw it,here is few options
Use context.getImageData to grab the whole canvas, resize the
canvas, then use context.putImageData to redraw it at the new scale.
Create a new canvas with the updated size and call
context.drawImage(oldCanvas, ...) to copy the old canvas onto the
new one.
call context.setScale(xscale, yscale) and call whatever function you
used to draw the canvas originally. Assuming you set up xscale and
yscale correctly, it will automatically scale everything to the new
size.
A quick solution to your problem is to calculate canvas height before drawing the text, because as you use canvas.height the canvas will be erased
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var myheight = 10;
for(var i = 0; 10 > i; i++){
myheight += 10;
}
canvas.height = myheight;
myheight = 10;
for(var i = 0; 10 > i; i++){
context.fillText("my text", 10, myheight);
myheight += 10;
}
http://jsfiddle.net/borja204/66dn06tq/1/
I am having trouble adding boxes dynamically to an HTML canvas. There should be a random amount of boxes, in random positions, of random colors.
The goal of what I am doing with the boxes is to be able to move them.
Essentially I am really lost.
Here is the html code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ramdom Boxes</title>
<script src="A2Q1.js"></script>
</head>
<body>
</body>
</html>
Here is the Javascript code:
window.onload = init;
function init() {
//when page is loaded create a bunch of boxes randomly throughout the page
//get the body element of the document
var body = document.getElementsByTagName("body")[0];
//create the canvas tag
var canvas = document.createElement("canvas");
canvas.height = 666;
canvas.width = 1346;
var context = canvas.getContext("2d");
//create the random boxes and append onto the canvas
var randNum = Math.floor(Math.random() * 1000 + 1);
var boxes = [];
for(var i=0;i<randNum;i++){
boxes[i].height = 50;
boxes[i].width = 50;
boxes[i].x = Math.floor(Math.random() * (1346 - boxes[i].width));
boxes[i].y = Math.floor(Math.random() * (666 - boxes[i].height));
boxes[i].colour = '#'+ Math.round(0xffffff * Math.random()).toString(16);
}
for(var i=0;i<boxes.length;i++){
context.fillStyle = colour;
context.fillRect(boxes[i].x, boxes[i].y, , boxes[i].height);
}
//append the canvas onto the body
body.appendChild(canvas);
}
Nothing is showing up on the page, through debugging it seems it is having issues with the properties. I am not sure where to go from here.
You can use masonry jquery plugin to sort boxes.
context.fillStyle = colour;
Did you mean
context.fillStyle = boxes[i].colour;