Random cutouts with HTML5 Canvas - html

All I'm trying to do is to get random cutouts (different shapes) via HTML Canvas element.
On the page I have a DIV, and above it I have the canvas element. So far I was able to color the element and cut out the first piece (not random), and wipe/clean the canvas again, but when I'm trying to do the exact same thing multiple times, it wouldn't work :/
Here is the half-working example: http://plnkr.co/edit/a5UAutd2jNgHMTtPMsp4
var cutThatOut = function(coords) {
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.globalCompositeOperation = "destination-out";
coords.forEach(function(coord, i){
if (i==0) {
ctx.moveTo(coord.x, coord.y);
} else {
ctx.lineTo(coord.x, coord.y);
}
});
ctx.fill();
}
thanks for your time/help

Several fixes:
Start your new set of path commands with ctx.beginPath. Otherwise your previous sets of drawing commands will be repeated along with the newest set.
Make sure you reset compositing at the end of cutThatOut. Otherwise your next fillRect(0,0,c.width,c.height) will "erase" the whole canvas because it's still using 'destination-out'.
If you want to do a completely new cutout with each call to cutThatOut then refill the canvas with black at the start of cutThatOut
Just a note: Your random coordinates often cause intersecting sides of the polygon and often extend outside the boundaries of the canvas.
Here's example code and a Demo:
var c = document.getElementById("canvas");
var ctx = c.getContext('2d');
var cutThatOut = function(coords) {
ctx.fillStyle = "black";
ctx.fillRect(0,0,c.width, c.height);
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.globalCompositeOperation = "destination-out";
ctx.beginPath();
coords.forEach(function(coord, i){
if (i==0) {
ctx.moveTo(coord.x, coord.y);
} else {
ctx.lineTo(coord.x, coord.y);
}
});
ctx.fill();
ctx.globalCompositeOperation = "source-over";
}
var wipeIt = function() {
ctx.clearRect(0,0,c.width,c.height);
}
var getRand = function(min, max) {return Math.round(Math.random() * (max - min) + min);}
cutThatOut([
{x:c.width/2, y:0},
{x:c.width,y:c.height/2},
{x:c.width/2,y:c.height},
{x:0, y:c.height/2}
]);
$("#btn").on("click", function(){
wipeIt();
cutThatOut([
{x:getRand(1,200), y:getRand(1,200)},
{x:getRand(1,200), y:getRand(1,200)},
{x:getRand(1,200), y:getRand(1,200)},
{x:getRand(1,200), y:getRand(1,200)}
]);
});
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
.adiv {
width: 200px;
height: 200px;
background-color: yellow;
position: relative;
}
#canvas {
width: 200px;
height: 200px;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="adiv">
<canvas id="canvas"></canvas>
</div>
<p>
<button id="btn">NEXT!</button>
</p>

Related

HTML Canvas Compositing: Reveal canvas image underneath another canvas

I'm new to the HTML canvas element, but have been working with it for the last two days. I'm working in Django and my mission is to reveal an image (loaded onto a canvas) that is hidden beneath another canvas (a pure white rectangle) as the mouse moves over the canvas stack. Both canvases are the exact same width and height.
I'd also like to be able to set the shape (square or circle) and dimensions of the cursor when it does the "erasing" of the top canvas (reveals the image underneath).
I've taken a look at the answer to a similar question but am a bit lost on the javascript written in the linked fiddle. My HandleMouseMove function is my initial attempt at trying to identify mouse placement in the top canvas. Any guidance would be really appreciated and thanks in advance. Here is what I have so far:
window.onload = function() {
//Create Bottom canvas & context
var canvas = document.getElementById('canvas');
var ctxB = canvas.getContext('2d');
//Create Top canvas & context
var canvas2 = document.getElementById('canvas2');
var ctxT = canvas2.getContext('2d');
//Set waterfall image variable
var waterfall = document.getElementById('waterfall');
//Set canvas w&h properties
canvas.width = canvas2.width = waterfall.width;
canvas.height = canvas2.height = waterfall.height;
//Populate Bottom canvas with image
ctxB.drawImage(waterfall, 0, 0, canvas.width, canvas.height);
//Populate Top canvas with white rectangle
ctxT.fillStyle = "white";
ctxT.fillRect(0, 0, canvas2.width, canvas2.height);
}
//Show Coordinates of mouse on Top canvas
function HandleMouseMove(event) {
var x = event.clientX;
var y = event.clientY;
var coords = x + ", " + y;
document.getElementById("demo").innerHTML = coords;
}
//Erase Top canvas to reveal waterfall
#stack {
position: relative;
}
#stack > canvas {
position: absolute;
display: block;
width: 40%;
margin-left: auto;
margin-right: auto;
margin-top: 25px;
}
<!DOCTYPE html>
{% load static %}
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="{% static 'entrance/entrance.css' %}">
<script src="{% static 'entrance/entrance.js' %}"></script>
</head>
<body>
<p hidden>
<img src="{% static 'entrance/Waterfall.jpg' %}" alt="issue here" id="waterfall" />
</p>
<p id="demo"></p>
<div id="stack">
<canvas id="canvas"></canvas>
<canvas id="canvas2" onmousemove="HandleMouseMove(event)"></canvas>
</div>
</body>
</html>
window.onload = function() {
//Create Bottom canvas & context
var canvas = document.getElementById('canvas');
var ctxB = canvas.getContext('2d');
//Create Top canvas & context
var canvas2 = document.getElementById('canvas2');
var ctxT = canvas2.getContext('2d');
//Set waterfall image variable
var waterfall = document.getElementById('waterfall');
//Set canvas w&h properties
canvas.width = canvas2.width = waterfall.width;
canvas.height = canvas2.height = waterfall.height;
//Populate Bottom canvas with image
ctxB.drawImage(waterfall, 0, 0, canvas.width, canvas.height);
//Populate Top canvas with white rectangle
ctxT.fillStyle = "white";
ctxT.fillRect(0, 0, canvas2.width, canvas2.height);
canvas2.addEventListener('mousemove', event => {
var x = event.offsetX;
var y = event.offsetY;
var coords = x + ", " + y;
document.getElementById("demo").innerHTML = coords;
//Erase Top canvas to reveal waterfall
const eraseSize = 15;
ctxT.clearRect(x - eraseSize/2, y - eraseSize/2, eraseSize, eraseSize);
})
}
#stack {
position: relative;
}
#stack > canvas {
position: absolute;
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 25px;
}
<p hidden>
<img src="http://vignette4.wikia.nocookie.net/plantsvszombies/images/8/8f/Kiwi_bird.png" alt="issue here" id="waterfall" />
</p>
<p id="demo"></p>
<div id="stack">
<canvas id="canvas"></canvas>
<canvas id="canvas2"></canvas>
</div>
For change shape, set globalCompositeOperation = 'destination-out' for top canvas:
ctxT.globalCompositeOperation = 'destination-out';
then draw any shape you want. For example, a circle:
ctxT.beginPath();
ctxT.arc(x, y, eraseSize, 0, Math.PI*2, false);
ctxT.fill();
ctxT.closePath();
instead of
ctxT.clearRect(x - eraseSize/2, y - eraseSize/2, eraseSize, eraseSize);

Canvas element not showing up

I'm very new to programming and am trying to make a project for class using html, canvas, and a css file. The concept is that there should be a title screen that appears in the canvas element that once you click will disappear and reveal a room where there are elements that you can hover your mouse over and get information.
I have the html, canvas, and css up to how I want it but whenever I try to put something in the canvas element it doesn't show up. Like, for the title screen I want to draw a colored box and put some text in it and then have it click away to reveal an image underneath. I used a drawCanvas but it will only show up if I put a gameLoop at the end. But when I try to add text, it disappears. Again, I'm really new to this and I'm sorry for my wall of text but any advice or suggestions would be really helpful. Here's my html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title Page</title>
<link rel="stylesheet" type="text/css" href="css.css"/>
<script src="js/modernizr.js"></script>
<script>
window.addEventListener("load",eventWindowLoaded, false);
function eventWindowLoaded() {
canvasApp();
}
function canvasSupport() {
return Modernizr.canvas;
}
function canvasApp() {
if (!canvasSupport()) {
return;
}
var theCanvas = document.getElementById("canvasOne");
var context = theCanvas.getContext("2d");
var width=1000;
var height=450;
function drawCanvas(){
context.fillStyle="teal";
context.fillRect(0,0,width,height);
setColor();
drawLines();
}
function gameLoop(){
requestAnimationFrame(gameLoop);
drawCanvas();
}
gameLoop();
}
</script>
</head>
<body>
<audio loop="loop" autoplay="autoplay" controls="controls">
<source src="themesong.mp3" type="audio/mpeg">
Your browser does not support the audio content.
</audio>
<!-- Canvas -->
<div id="canvas-container">
<canvas id="canvasOne" width="1000" height="450">
Your browser does not support canvas.
</canvas>
</div>
<!-- ^ End Canvas -->
</body>
</html>
And here's my CSS:
#canvasOne {
background-color: #cccccc;
border: 10px solid rgba(136, 128, 172, 0.9);
margin-left: 210px;
margin-right: auto;
margin-top: 130px;
#body {
background-image: url("mansion.jpg");
background-repeat: no-repeat;
}
Honestly, if someone could just help me put an image in the canvas and make it so that certain areas where the mouse hovers over a text box would appear, would be awesome. The idea is that it's a game where you "look" around the room with your mouse for clues. And once again, I'm very new to this so sorry if this is formatted weird or my question is too ridiculously long.
I'm not sure what exactly you want but i fixed the problem where the image is not coming up on the canvas.
The problem is that on your CSS you are coloring the background then you are also putting the image on it causing it to overlap.
Here is the CSS code that I have changed:
#canvasOne {
background-image: url("mansion.jpg");
background-repeat: no-repeat;
border: 10px solid rgba(136, 128, 172, 0.9);
margin-left: 210px;
margin-right: auto;
margin-top: 130px;
}
I dont know how to do the hover part but you should look into this
This is your main problem:
window.addEventListener("load",eventWindowLoaded, false);
The reason I say that is because you are calling the evenWindowLoaded function once -- when the page initially loads. Since this is the case, whatever state the drawLines() and other functions are in when the page loads for the first time, that will be draw on the canvas.
Instead you should try to use this:
var timer = setInterval(function() { eventWindowLoaded(); }, 100);
and then clear the canvas and re-draw it.
(this is for the hover effect)
that way, you can do calculate if the mouse's cursor is above a particular space on the canvas and then do whatever functions if it is... this isn't 100% going to work, but its a general idea of what you could do:
var mousePos;
var timer = setInterval(function() { eventWindowLoaded(); }, 100);
function eventWindowLoaded() {
context.clearRect(0,0,width,height);
for (var i=0; i<images.count; ++i) {
var img = images[i];
if (Math.Abs(mousePos.x - img.Pos().x)) <= img.width) {
if (Math.Abs(mousePos.y - img.Pos().y)) <= img.height) {
do_hover_event();
}
}
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
mousePos = getMousePos(canvas, evt);
}
Thats one thing -- here's another:
You are leaving the scope of the variable definition for the canvas/context var's, try this method for the canvas/context -- using 3 diffeerent separate functions and defining the width, height, theCanvas, and context all in the global scope
var width=1000;
var height=450;
var theCanvas = document.getElementById("canvasOne");
var context = theCanvas.getContext("2d");
function canvasApp() {
if (!canvasSupport()) {
return;
}
gameLoop();
}
function drawCanvas(){
context.fillStyle="teal";
context.fillRect(0,0,width,height);
setColor();
drawLines();
}
function gameLoop(){
requestAnimationFrame(gameLoop);
drawCanvas();
}

Create soft round circles HTML5

I created circles using HTML5 Canvas. I want them to look like the soft, round brushes done with Photoshop. In this code, I can only create the circles with specific opacity:
function drawClusters(ctx) {
var startPoint = (Math.PI/180)*0;
var endPoint = (Math.PI/180)*360;
ctx.beginPath();
ctx.arc(30,30,10,startPoint,endPoint,true); // x, y, r
ctx.fillStyle = "rgb(255,255,204)";
ctx.globalAlpha = 0.5;
ctx.fill();
ctx.closePath();
}
How is it possible to achieve the soft round effect? Something like the following image:
http://jsfiddle.net/pr9r7/2/ - v2, fixed overlaping issue.
function my_circle(ctx, x, y, size, color1, color2){
var color1_rgb = hex2rgb(color1);
var color2_rgb = hex2rgb(color2);
var radgrad = ctx.createRadialGradient(
x, y, size*0,
x, y, size);
radgrad.addColorStop(0, "rgba("+color1_rgb.r+", "+color1_rgb.g+", "+color1_rgb.b+", 1)");
radgrad.addColorStop(1, "rgba("+color2_rgb.r+", "+color2_rgb.g+", "+color2_rgb.b+", 0)");
ctx.fillStyle = radgrad;
ctx.fillRect(x-size,y-size,size*2,size*2);
}
This is probably not the answer (because it does not use canvas, but plain HTML and CSS), however your question made me play a little :)
http://jsfiddle.net/n5axu/
A DIV can be styled with the box-shadow css property to get similar circles.
HTML
<div class="circle white"></div>
CSS
.circle {
height: 0;
width: 0;
box-shadow: 0 0 70px 60px;
position: fixed;
}
.circle.white { color: white; }
body { background-color: black; }

Canvas not working as intended

I was trying a script to draw graph paper like grids on the canvas from dive into html5. The result is supposed to draw a mesh with squares of side 10px but i'm getting the size as approximately 20px, and not exact squares.
Here is the code,`
<html>
<head>
<style>
body{
margin: 20px 20px 20px 20px;
}
canvas{
width: 500px;
height: 375px;
border: 1px solid #000;
}
</style>
<script type="text/javascript">
function activate(){
var canvas =document.getElementById("exp");
var context = canvas.getContext("2d");
for (var x=0.5;x<500;x+=10){
context.moveTo(x,0);
context.lineTo(x,375);
console.log(x);
}
for (var y=0.5;y<375;y+=10){
context.moveTo(0,y);
context.lineTo(500,y);
}
context.strokeStyle="#000";
context.stroke();
}
</script>
</head>
<body>
<canvas id="exp"><script type="text/javascript">activate();</script></canvas>
</body
</html>
And this is the output:
while the actual output should be:
Note: i'm not worried about the color difference. what i don't understand is why the space between 2 lines is ~20px(as checked by a measurement tool on firefox) instead of 10px.
Also, on printing the values of x, it gives the right value(i.e. incremented by 10 each time).
you can not set the canvas' size with css
you should set in the DOM's attribute.
<canvas width="100" height="200"></canvas>
Javascript can calculate for you. Only set the parameters:
html:
<canvas id="exp"></canvas>
js:
function activate(id, xcount, ycount, width, color) {
var canvas = document.getElementById(id);
var context = canvas.getContext("2d");
canvas.width = xcount * width + 1;
canvas.height = ycount * width + 1;
for (var x = 0.5; x < canvas.width; x += width) {
context.moveTo(x, 0);
context.lineTo(x, canvas.height);
}
for (var y = 0.5; y < canvas.height; y += width) {
context.moveTo(0, y);
context.lineTo(canvas.width, y);
}
context.strokeStyle = color;
context.stroke();
}
activate("exp", 37, 50, 10, "#ccc");
Also see this example.

html5 - drag a canvas

I have a huge HTML5 Canvas, and I want it to work like google maps: the user can drag it and see only a small part of it (the screen's size) all the time. it renders only the part you can see on the screen.
how can I do it? do you have an idea?
2 simple steps:
place the canvas inside a div container with overflow:hidden
use any method to make your canvas draggable (I will use jQuery UI)
To follow my method you need to go to the jQuery UI website and download any version of the jQuery UI (you can create a custom version only consisting of the UI Core and Draggable Interaction for this example.)
Unpack the .zip file and move the 'js' folder to your page directory.
Inlcude the .js files contained in the folder into your page.
Place the following code between your <head></head>-tags to get your canvas draggable:
<script type="text/javacript">
$(function() {
$("#CanvasID").draggable();
});
</script>
Here's an example:
<!DOCTYPE>
<html>
<head>
<title>canvas test</title>
<script type="text/javascript" src="js/jquery-1.5.1.min.js"></script> <!-- include the jQuery framework -->
<script type="text/javascript" src="js/jquery-ui-1.8.11.custom.min.js"></script> <!-- include JQuery UI -->
<style type="text/css">
#box{
width: 400px;
height: 400px;
border:5px solid black;
overflow:hidden;
position:relative;
} /* Just some basic styling for demonstration purpose */
</style>
<script type="text/javascript">
window.onload = function() {
var drawingCanvas = document.getElementById('myDrawing');
// Check the element is in the DOM and the browser supports canvas
if(drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
var context = drawingCanvas.getContext('2d');
context.strokeStyle = "#000000";
context.fillStyle = "#FFFF00";
context.beginPath();
context.arc(200,200,200,0,Math.PI*2,true);
context.closePath();
context.stroke();
context.fill();
}
// just a simple canvas
$(function() {
$( "#myDrawing" ).draggable();
});
// make the canvas draggable
}
</script>
</head>
<body>
<div id="box">
<canvas id="myDrawing" width="800" height="800">
<p>Your browser doesn't support canvas.</p>
</canvas>
</div>
</body>
</html>
Hope this get's you going.
note: This is just a basic example. This will still need some editing. For example the user can drag the canvas totally out of the viewport (perhaps constraining the Canvas to the div may do the trick?). But this should be a good starting point.
I would use two canvases. Keep your huge source canvas hidden and copy portions of it to a second smaller visible canvas. Here's my quickly hacked-up proof of concept:
<!DOCTYPE HTML>
<html>
<head>
<title>canvas scroll</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
overflow: hidden;
}
#source {
display: none;
}
#coords{
position: absolute;
top: 10px;
left: 10px;
z-index: 2;
}
#coords p{
background: #fff;
}
</style>
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
var $window;
var img;
var $source; var source; var sourceContext;
var $target; var target; var targetContext;
var scroll = {
x : 0,
y : 0
};
var scrollMax;
function init() {
// Get DOM elements
$window = $(window);
$source = $('canvas#source');
source = $source[0];
sourceContext = source.getContext("2d");
$target = $('canvas#target');
target = $target[0];
targetContext = target.getContext("2d");
// Draw something in source canvas
sourceContext.rect(0, 0, source.width, source.height);
var grd = sourceContext.createLinearGradient(0, 0, source.width, source.height);
grd.addColorStop(0, '#800080');
grd.addColorStop(0.125, '#4B0082');
grd.addColorStop(0.25, '#0000FF');
grd.addColorStop(0.325, '#008000');
grd.addColorStop(0.5, '#FFFF00');
grd.addColorStop(0.625, '#FFA500');
grd.addColorStop(0.75, '#FF0000');
grd.addColorStop(0.825, '#800080');
sourceContext.fillStyle = grd;
sourceContext.fill();
/*
* Setup drag listening for target canvas to scroll over source canvas
*/
function onDragging(event){
var delta = {
left : (event.clientX - event.data.lastCoord.left),
top : (event.clientY - event.data.lastCoord.top)
};
var dx = scroll.x - delta.left;
if (dx < 0) {
scroll.x = 0;
} else if (dx > scrollMax.x) {
scroll.x = scrollMax.x;
} else {
scroll.x = dx;
}
var dy = scroll.y - delta.top;
if (dy < 0) {
scroll.y = 0;
} else if (dy > scrollMax.y) {
scroll.y = scrollMax.y;
} else {
scroll.y = dy;
}
event.data.lastCoord = {
left : event.clientX,
top : event.clientY
}
draw();
}
function onDragEnd(){
$(document).unbind("mousemove", onDragging);
$(document).unbind("mouseup", onDragEnd);
}
function onDragStart(event){
event.data = {
lastCoord:{
left : event.clientX,
top : event.clientY
}
};
$(document).bind("mouseup", event.data, onDragEnd);
$(document).bind("mousemove", event.data, onDragging);
}
$target.bind('mousedown', onDragStart);
/*
* Draw initial view of source canvas onto target canvas
*/
$window.resize(draw);
$window.trigger("resize");
}
function draw() {
target.width = $window.width();
target.height = $window.height();
if(!scrollMax){
scrollMax = {
x: source.width - target.width,
y: source.height - target.height
}
}
targetContext.drawImage(source, scroll.x, scroll.y, target.width, target.height, 0, 0, target.width, target.height);
$('#x').html(scroll.x);
$('#y').html(scroll.y);
}
$(document).ready(init);
</script>
</head>
<body>
<div id="coords">
<p>Drag the gradient with the mouse</p>
<p>x: <span id="x"></span></p>
<p>y: <span id="y"></span></p>
</div>
<canvas id="source" width="4000" height="4000"></canvas>
<canvas id="target"></canvas>
</body>
</html>