Drawing on canvas does not happen in javascript - javascript

I'm trying to make a canvas of squers and rectangles that appear randomly, the amount of them is the users choice. after they input the numbers of eace of them, press a button-it should appear on the canvas. in my code it does not happen, and i cant understand why! making me crazy here. I'm obviously missing something here, and i guess its a very stupid thing.
function draw() {
var drawing = document.getElementById("canvas");
var context = drawing.getContext("2d");
saveImage();
}
//save the user input to use it later
var numOfRect = parseInt(document.getElementById("inSquer").value);
var numOfCirc = parseInt(document.getElementById("inCircle").value);
//This function will draw on the canvas
function paint(numOfRect, numOfCirc) {
for (var makeIt = 0; makeIt < numOfRect; makeIt++) {
makeRect(drawing, context);
makeCircle(drawing, context);
}
}
//This function draw the circles
function makeCircle(drawing, context) {
var radius = Math.floor(Math.random() * 80);
var x = Math.floor(Math.random() * canvas.width);
var y = Math.floor(Math.random() * canvas.height);
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI);
context.fillStyle = "blue";
context.fill();
}
//This function draw the squers
function makeRect(drawing, context) {
var w = Math.floor(Math.random() * 50);
var x = Math.floor(Math.random() * canvas.width);
var y = Math.floor(Math.random() * canvas.height);
context.fillStyle = "yellow";
context.fillRect(x, y, w, w);
}
//function to save the canvas as an image
function saveImage() {
var canvas = document.getElementById("canvas");
canvas.onclick = function() {
window.location = canvas.toDataURL("image/png");
};
}
#canvas {
margin-left: 150px;
border: 1px solid black;
}
<html>
<head>
<script src="js.js">
</script>
<link href="design.css" rel="stylesheet" />
</head>
<body onload="draw()">
<canvas id="canvas" width="1200" height="750"></canvas>
</br>
</br>
<span>
How many Circles do you want?
<input id="inCircle"></input>
</span>
</br>
How many Squers do you want?
<input id="inSquer"></input>
</br>
<button id="creat" onclick="paint()">Creat My Work</button>
</body>
</html>

paint(numOfRect, numOfCirc) wants 2 parameters, but <button id="creat" onclick="paint()">Creat My Work</button> is not giving any.
Also
var numOfRect = parseInt(document.getElementById("inSquer").value);
var numOfCirc = parseInt(document.getElementById("inCircle").value);
does not exactly do anything, as the values are empty when that code runs.
Try changing the paint function like so:
function paint()
{
var numOfRect = parseInt(document.getElementById("inSquer").value);
var numOfCirc = parseInt(document.getElementById("inCircle").value);
for (var makeIt = 0; makeIt < numOfRect; makeIt++)
{
makeRect(drawing, context);
makeCircle(drawing, context);
}
}

Please consider the following snippet.
First of all, your paint() function was missing two arguments. Apart from that, I would recommend to define all the variables on top of your script, so it's easier to keep track.
I have added a few comments in the code to highlight the changes.
Also I have removed a few redundant DOM interactions.
// Wait for DOM to be loaded.
document.addEventListener("DOMContentLoaded", function(event) {
// Keep references to elements, so we could interact with them later.
var drawing = document.getElementById("canvas");
var context = drawing.getContext("2d");
var inSquer = document.getElementById("inSquer");
var inCircle = document.getElementById("inCircle");
var button = document.getElementById("creat");
// Attach event listeners to the button and canvas element.
button.addEventListener("click", function() {
// Retrieve values from input fields every time you click.
paint(parseInt(inSquer.value), parseInt(inCircle.value));
});
drawing.addEventListener("click", function() {
saveImage();
});
// Function to save the canvas as an image.
function saveImage() {
window.location = drawing.toDataURL("image/png");
}
// This function will draw on the canvas.
function paint(numOfRect, numOfCirc) {
for (var makeIt = 0; makeIt < numOfRect; makeIt++) {
makeRect(drawing, context);
makeCircle(drawing, context);
}
}
// This function draw the circles.
function makeCircle(drawing, context) {
var radius = Math.floor(Math.random() * 80);
var x = Math.floor(Math.random() * canvas.width);
var y = Math.floor(Math.random() * canvas.height);
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI);
context.fillStyle = "blue";
context.fill();
}
// This function draw the squers.
function makeRect(drawing, context) {
var w = Math.floor(Math.random() * 50);
var x = Math.floor(Math.random() * canvas.width);
var y = Math.floor(Math.random() * canvas.height);
context.fillStyle = "yellow";
context.fillRect(x, y, w, w);
}
});
#canvas {
margin-left: 150px;
border: 1px solid black;
}
<html>
<head>
</head>
<body>
<canvas id="canvas" width="1200" height="750"></canvas>
<br/>
<br/>
<span>
How many Circles do you want?
<input id="inCircle" />
</span>
<br/>How many Squers do you want?
<input id="inSquer" />
<br/>
<button id="creat">Creat My Work</button>
</body>
</html>

Related

Show HTML Slider variable derived through javascript on HTML Page

I have a slider that changes the width of circles on a bullseye on a canvas. I want to display that bandwidth beneath the canvas. Like just a simple Current bandwidth: x
I am having trouble figuring out how to do this.
I've tried using span and documentwrite(), but part of the problem is I can't really figure out how to get the variable in the first place.
<!DOCTYPE html>
<html>
<head>
<script src="bullseye.js"></script>
<title>Bull's Eye</title>
</head>
<body>
<canvas id="testCanvas" style="border: 1px solid;" width="400" height="400"> </canvas>
<p></p>
<div style="position:absolute; top:420px; left:10px">
<label for="radius">Bandwidth</label>
<input type="range" id="width" min="5" max="50" step="5" value="25" oninput="sliderModule.drawPattern()"></input>
<p>Current Bandwidth: <span id="show"></span></p>
</div>
</body>
</html>
here is the javascript
var sliderModule = (function(win, doc) {
win.onload = init;
// canvas and context variables
var canvas;
var context;
// center of the pattern
var centerX, centerY;
function init() {
canvas = doc.getElementById("testCanvas");
context = canvas.getContext("2d");
centerX = canvas.width / 2;
centerY = canvas.height / 2;
drawPattern();
}
function drawPattern() {
var width = doc.getElementById("width").value;
var radius = 200;
var colorTog = 1;
context.clearRect(0, 0, canvas.width, canvas.height);
while (radius > 0) {
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI);
if (colorTog == 1){
context.fillStyle = 'red';
} else {
context.fillStyle = 'blue';
}
context.fill();
context.closePath();
radius = radius - width;
if (colorTog == 1){
colorTog = 0;
} else {
colorTog = 1;
}
}
}
return {
drawPattern: drawPattern
};
})(window, document);

Remove point on double click on canvas

I have a canvas on which user can draw point on click on any part of it. As one know we must give the user the possibility to undo an action that he as done. This is where I'am stuck, how can I program the codes to allow the user to remove the point on double click on the the point he wants to remove ?
<canvas id="canvas" width="160" height="160" style="cursor:crosshair;"></canvas>
1- Codes to draw the canvas and load an image in it
var canvasOjo1 = document.getElementById('canvas'),
context1 = canvasOjo1.getContext('2d');
ojo1();
function ojo1()
{
base_image1 = new Image();
base_image1.src = 'https://www.admedicall.com.do/admedicall_v1//assets/img/patients-pictures/620236447.jpg';
base_image1.onload = function(){
context1.drawImage(base_image1, 0, 0);
}
}
2- Codes to draw the points
$("#canvas").click(function(e){
getPosition(e);
});
var pointSize = 3;
function getPosition(event){
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
drawCoordinates(x,y);
}
function drawCoordinates(x,y){
var ctx = document.getElementById("canvas").getContext("2d");
ctx.fillStyle = "#ff2626"; // Red color
ctx.beginPath();
ctx.arc(x, y, pointSize, 0, Math.PI * 2, true);
ctx.fill();
}
My fiddle :http://jsfiddle.net/xpvt214o/834918/
By hover the mouse over the image we see a cross to create the point.
How can i remove a point if i want to after create it on double click ?
Thank you in advance.
Please read first this answer how to differentiate single click event and double click event because this is a tricky thing.
For the sake of clarity I've simplified your code by removing irrelevant things.
Also please read the comments of my code.
let pointSize = 3;
var points = [];
var timeout = 300;
var clicks = 0;
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let cw = (canvas.width = 160);
let ch = (canvas.height = 160);
function getPosition(event) {
var rect = canvas.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top
};
}
function drawCoordinates(point, r) {
ctx.fillStyle = "#ff2626"; // Red color
ctx.beginPath();
ctx.arc(point.x, point.y, r, 0, Math.PI * 2, true);
ctx.fill();
}
canvas.addEventListener("click", function(e) {
clicks++;
var m = getPosition(e);
// this point won't be added to the points array
// it's here only to mark the point on click since otherwise it will appear with a delay equal to the timeout
drawCoordinates(m, pointSize);
if (clicks == 1) {
setTimeout(function() {
if (clicks == 1) {
// on click add a new point to the points array
points.push(m);
} else { // on double click
// 1. check if point in path
for (let i = 0; i < points.length; i++) {
ctx.beginPath();
ctx.arc(points[i].x, points[i].y, pointSize, 0, Math.PI * 2, true);
if (ctx.isPointInPath(m.x, m.y)) {
points.splice(i, 1); // remove the point from the array
break;// if a point is found and removed, break the loop. No need to check any further.
}
}
//clear the canvas
ctx.clearRect(0, 0, cw, ch);
}
points.map(p => {
drawCoordinates(p, pointSize);
});
clicks = 0;
}, timeout);
}
});
body {
background: #20262E;
padding: 20px;
}
<canvas id="canvas" style="cursor:crosshair;border:1px solid white"></canvas>

Drawing a 'bullseye' in HTML5 Canvas using javascript

I'm struggling a bit to get this to work. I have a 'Canvas' element on my web page, and I need to 'draw' filled circles within each other. I need to use a loop to draw the pattern, alternating between red and blue filled circles. It will use the initial band width value of 25. It will repeat the loop as long as the current radius is greater than 0. It will use a slider to control the band width. The slider has a minimum value of 5,
maximum value of 50 with step 5, and current value as 25. As the value of
the slider changes, it draws the pattern with the current bandwidth. I can make this work with gradients, but that does not do what I need it to do and it does not look right. Here is what I have so far:
var sliderModule = (function(win, doc) {
win.onload = init;
// canvas and context variables
var context;
// center of the pattern
var centerX, centerY;
function init() {
canvas = doc.getElementById("canvas");
context = canvas.getContext("2d");
centerX = canvas.width / 2;
centerY = canvas.height / 2;
// draw the initial pattern
//drawPattern();
}
// called whenever the slider value changes
function drawPattern() {
var canvas;
// clear the drawing area
context.clearRect(0, 0, canvas.width, canvas.height);
// get the current radius
var radius = doc.getElementById("radius").value;
// set fill color to red
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const colors = ['#F00', '#0F0', '#00F'];
const outerRadius = 100;
let bandSize = 10; // this would be where you put the value for your slider
for (let r = outerRadius, colorIndex = 0; r > 0; r -= bandSize, colorIndex = (colorIndex + 1) % colors.length) {
ctx.fillStyle = colors[colorIndex];
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, r, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
}
return {
drawPattern: drawPattern
};
})
(window, document);
<!doctype html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<script src="bullsEye.js"></script>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<label for="bandwidth">BandWidth:</label>
<input type="range" id="radius" min="5" max="50" step="5" value="25" oninput="sliderModule.drawPattern()" />
</body>
</html>
var sliderModule = (function(win, doc) {
win.onload = init;
// canvas and context variables
var canvas;
var context;
// center of the pattern
var centerX, centerY;
function init() {
canvas = doc.getElementById("testCanvas");
context = canvas.getContext("2d");
centerX = canvas.width / 2;
centerY = canvas.height / 2;
// draw the initial pattern
drawPattern();
}
// called whenever the slider value changes
function drawPattern() {
// clear the drawing area
context.clearRect(0, 0, canvas.width, canvas.height);
// get the current radius
var radius = doc.getElementById("radius").value;
// set fill color to red
context.fillStyle = '#FF0000';
// draw the pattern
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI);
context.fill();
context.closePath();
}
return {
drawPattern: drawPattern
};
})(window, document);
Your snippet doesn't quite work as provided, but given a value for your slider, you'll just reduce radius and loop while radius is greater than 0.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 200;
const colors = ['#F00', '#0F0', '#00F'];
const outerRadius = 100;
let bandSize = 10; // this would be where you put the value for your slider
for (let r = outerRadius, colorIndex = 0; r > 0; r -= bandSize, colorIndex = (colorIndex + 1) % colors.length) {
ctx.fillStyle = colors[colorIndex];
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, r, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
<canvas />
What you're missing is the loop which would change. To control the colors, I made an array, and in addition to changing my radius each for-loop iterator, I also change the colorIndex.
I use (colorIndex + 1) % colorIndex.length so it'll loop through each of them and not go beyond the index (it'll count 0, 1, 2, and back to 0). You can change or add colors to the array.

Erasing previously drawn lines on an HTML5 canvas

To play around with HTML5 canvas, I decided to make an app which draws an analogue clockface. Everything's fine, except that old lines don't get erased in the way that I would expect. I've included part of the code below - DrawHands() gets called once a second:
var hoursPoint = new Object();
var minutesPoint = new Object();
var secondsPoint = new Object();
function drawHands()
{
var now = new Date();
drawLine(centerX, centerY, secondsPoint.X, secondsPoint.Y, "white", 1);
var seconds = now.getSeconds();
secondsPoint = getOtherEndOfLine(centerX, centerY, 2 * Math.PI / 60 * seconds, 0.75 * radius);
drawLine(centerX, centerY, secondsPoint.X, secondsPoint.Y, "black", 1);
drawLine(centerX, centerY, minutesPoint.X, minutesPoint.Y, "white", 3);
var minutes = now.getMinutes();
minutesPoint = getOtherEndOfLine(centerX, centerY, 2 * Math.PI / 60 * minutes, 0.75 * radius);
drawLine(centerX, centerY, minutesPoint.X, minutesPoint.Y, "black", 3);
drawLine(centerX, centerY, hoursPoint.X, hoursPoint.Y, "white", 3);
var hours = now.getHours();
if (hours >= 12) { hours -= 12; } // Hours are 0-11
hoursPoint = getOtherEndOfLine(centerX, centerY, (2 * Math.PI / 12 * hours) + (2 * Math.PI / 12 / 60 * minutes), 0.6 * radius);
drawLine(centerX, centerY, hoursPoint.X, hoursPoint.Y, "black", 3);
}
To make sense of the above, there are two helper functions:
drawLine(x1, y1, x2, y2, color, thickness)
getOtherEndOfLine(x, y, angle, length)
The problem is that while all the hands get drawn as expected in black, they never get erased. I would expect that since the same line is drawn in white (the background colour) it would effectively erase what was previously drawn at that point. But this doesn't seem to be the case.
Anything I'm missing?
Instead of erasing the things you don't want you can:
save the state of the canvas
draw the things you don't want
restore the canvas to the saved state to 'erase' them
This can be accomplished pretty easily using ImageData:
var canvas = document.querySelector('canvas'),
context = canvas.getContext('2d');
context.fillStyle = 'blue';
context.fillRect(0,0,200,200);
// save the state of the canvas here
var imageData = context.getImageData(0,0,canvas.width,canvas.height);
// draw a red rectangle that we'll get rid of in a second
context.fillStyle = 'red';
context.fillRect(50,50,100,100);
setTimeout(function () {
// return the canvas to the state right after we drew the blue rect
context.putImageData(imageData, 0, 0);
}, 1000);
<canvas width=200 height=200>
For reasons that I could expand upon, you should consider clearing your canvas and redrawing it entirely unless there are performance or compositing reasons not to.
You want clearRect, something like this:
//clear the canvas so we can draw a fresh clock
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
//redraw your clock here
/* ... */
The reason you can't just redraw the line in white and hope for it to erase the old line is because there might be some anti-aliasing/bleeding. You'll also notice that a straight horizontal line drawn on a pixel versus a half-pixel looks very different because of this.
When you do your white "erase" lines, try drawing them with a larger lineWidth by about 3 or 4. That should work for your case.
You should also draw all of the white lines first, then all of the black lines, in case they intersect.
A quick and easy way to clear a canvas is to set the width:
context.canvas.width = context.canvas.width;
My solution is double buffering :
var shapes =
[{type:"circle", x:50, y:50, radious:40, lineWidth:2, strokeStyle:"#FF0000", fillStyle:"#800000"}
,{type:"rectangle", x:50, y:50, width:100, height: 100, lineWidth:2, strokeStyle:"#00FF00", fillStyle:"#008000"}
,{type:"line", x1:75, y1:100, x2:170, y2:75, lineWidth:3, strokeStyle:"#0000FF"}
];
step1();
setTimeout(function () {
step2();
setTimeout(function () {
step3();
}, 1000);
}, 1000);
function step1() {
clearCanvas('myCanvas1');
shapes.forEach((sh) => { drawShape('myCanvas1', sh); });
};
function step2() {
clearCanvas('myCanvas2');
shapes.pop();
shapes.forEach((sh) => { drawShape('myCanvas2', sh); });
showOtherCanvas('myCanvas2', 'myCanvas1');
};
function step3() {
clearCanvas('myCanvas1');
shapes.pop();
shapes.forEach((sh) => { drawShape('myCanvas1', sh); });
showOtherCanvas('myCanvas1', 'myCanvas2');
};
function showOtherCanvas(cnv1, cnv2) {
var c1 = document.getElementById(cnv1);
var c2 = document.getElementById(cnv2);
c1.style['z-index'] = 3;
c2.style['z-index'] = 1;
c1.style['z-index'] = 2;
}
function clearCanvas(canvasID) {
var canvas = document.getElementById(canvasID);
var ctx = canvas.getContext('2d');
ctx.fillStyle="#FFFFFF";
ctx.fillRect(0,0,480,320);
}
function drawShape (canvasID, info) {
switch (info.type) {
case "line" : drawLine(canvasID, info);
case "rectangle" : drawRectangle(canvasID, info);
case "circle" : drawCircle(canvasID, info);
}
}
function drawLine (canvasID, info) {
var canvas = document.getElementById(canvasID);
var ctx = canvas.getContext('2d');
ctx.strokeStyle = info.strokeStyle;
ctx.lineWidth = info.lineWidth
ctx.beginPath();
ctx.moveTo(info.x1, info.y1);
ctx.lineTo(info.x2, info.y2);
ctx.stroke();
}
function drawRectangle (canvasID, info) {
var canvas = document.getElementById(canvasID);
var ctx = canvas.getContext('2d');
ctx.fillStyle = info.fillStyle;
ctx.strokeStyle = info.strokeStyle;
ctx.lineWidth = info.lineWidth
ctx.fillRect(info.x, info.y, info.width, info.height);
ctx.strokeRect(info.x, info.y, info.width, info.height);
}
function drawCircle (canvasID, info) {
var canvas = document.getElementById(canvasID);
var ctx = canvas.getContext('2d');
ctx.fillStyle = info.fillStyle;
ctx.strokeStyle = info.strokeStyle;
ctx.lineWidth = info.lineWidth
ctx.beginPath();
ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
ctx.stroke();
}
<canvas id="myCanvas2" width="480" height="320"
style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:1">
</canvas>
<canvas id="myCanvas1" width="480" height="320"
style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:2">
</canvas>
The change is so fast you won't see any flicker.

How do I continuously update these coordinates?

I want to move the rectangle horizontally,however,it enters the updateStageObjects() function several times but does not update the value of myRectangle.x.How do I fix this?
<script type="text/javascript">
var interval = 10;
var x=0;
var y=0;
var myRectangle;
var context ;
var canvas;
function Rectangle(x, y, width, height, borderWidth) {
this.x=x;
this.y=y;
this.width = width;
this.height = height;
this.borderWidth = borderWidth;
}
function DrawRects(){
myRectangle = new Rectangle (250,70,100,50, 5); context.rect(myRectangle.x,myRectangle.y,myRectangle.width,myRectangle.height);
context.fillStyle="#8ED6FF";
context.fill();
context.lineWidth=myRectangle.borderWidth;
context.strokeStyle="black";
context.stroke();
}
function updateStageObjects() {
var amplitude = 150;
var centerX = 240;
myRectangle.x += 100;
alert(myRectangle.x+" "+myRectangle.y);
}
function clearCanvas() {
context.clearRect(0,0,canvas.width, canvas.height);
}
function DrawRect(){
setTimeout(CheckCanvas,10);
clearCanvas();
updateStageObjects();
DrawRects();
}
function CheckCanvas(){
return !!(document.createElement('canvas').getContext);
}
function CheckSound(){
return !!(document.createElement('sound').canPlayType)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function Checkstorage(){
return !!(window.localStorage)
}
function CheckVideo(){
return !!(document.createElement('video').canPlayType)
}
function DrawCanvas(){
if (CheckCanvas()){
canvas = document.getElementById('Canvas');
DrawRects();
setInterval(DrawRect, 10);
}
}
</script>
html
<canvas id="Canvas" width="800px" height="800px" onclick="DrawCanvas()"> Nor supported</canvas>
As Chris has pointed out your DrawRects() always draws the same co-ords, try adding a couple more variables like
var dx = 250;
var dy = 70;
Then change your new Rectangle to
myRectangle = new Rectangle (dx,dy,100,50, 5);
Next change your myRectangle.x += 100 line to
dx += 100;
Hope this helps.
Every time you call updateStageObjects(), it is followed immediately by a call to DrawRects(), which creates a new rectangle at exactly (250,70,100,50, 5). So you'll never notice it increment by 100.
You'll need to pass some numbers back and forth between these functions if you want one of them to remember the changes made in another.

Categories