Filter image smoothly in html5 canvas. - html

I need to have an image filtered and then with the mouse move erase the filter and leave the image on its original format.
For that I am thinking about having two canvas the one upon the other with
a relative transparent filter on the top.
<div style="position: relative;">
<canvas id="picture-layer" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas
<canvas id="filter-layer" width="100" height="100"
style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</div>
Then how can I erase the filter-layer filter on the mouse move and reveal the image from below ?

When the page loads, you could call a function that fills the filter canvas with a semi-transparent color. For example...
function fillFilterCanvas() {
var canvas = document.getElementById("filterCanvas");
var context = canvas.getContext("2d");
context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle = "rgba(0,0,0,0.75)";
context.fill();
}
When the mouse moves over the filter canvas, you could call a function that clears part of the filter canvas near the mouse position. For example...
function clearFilterCanvas(x, y) {
var canvas = document.getElementById("filterCanvas");
var context = canvas.getContext("2d");
var width = 20;
var height = 20;
context.clearRect(x - width / 2, y - height / 2, width, height);
}
From the mouse move event handler, you would call the clearFilterCanvas() function with the mouse's position in the filter canvas. For example...
function filterCanvas_mousemove(e) {
clearFilterCanvas(e.offsetX, e.offsetY);
}

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);

How do I draw <div> elements on top of a three.js canvas with a transparent background?

I was reading this answer but the approach proposed is purely theoretical. In my HTML5 code I've tried something like this:
<div id='gameCanvas'>
<div id="insideText">First trial</div>
</div>
and in the CSS I've put this:
#insideText{
background-color: transparent;
}
I'm quite a newbie when it comes to HTML/CSS, so I'm probably making some easy mistake, but this way I get a black line above my canvas, and the text appears in that black line. I want the text to appear over the canvas without this black line, and I would also like to know how to place some text on different areas of the canvas (my canvas is not fullscreen).
Edit:
If I put the <div> outside the canvas element it appears with a transparent background indeed, but always as a separate element from the canvas.
Your question isn't specific to three or canvas. It's just a basic HTML/CSS question which I'm sure is answered 1000 times on this site but since search sucks I'll answer again and leave it to someone with more patience to close as a dupe
To make 2 or more elements overlap you generally need a parent element. That element has to have css position: relative; or position:absolute;. That makes it the anchor/origin/base for its children. Note: <body> is already marked this way.
Then for all the children you can use position:absolute and set their positions with left, top, right, or bottom
Example
const ctx = document.querySelector('canvas').getContext('2d');
ctx.fillStyle = 'yellow';
ctx.fillRect(0, 0, 300, 150);
ctx.fillStyle = 'red';
ctx.arc(150, 75, 125, 0, Math.PI * 2, true);
ctx.fill();
<h1>Some text</h1>
<div style="position: relative; display: inline-block;">
<canvas></canvas>
<div style="position: absolute; left: 1em; top: 1em;">foo</div>
<div style="position: absolute; right: 1em; bottom: 1em;">bar</div>
</div>
note: the display: inline-block; is to make the outer element fit the content rather than stretch to width of its parent (the body in this case). There are 100s of other ways to set the size of elements.
note that elements are transparent by default so no need to set the background color as transparent unless you set it somewhere else as non-transparent
const renderer = new THREE.WebGLRenderer();
document.querySelector('#gameCanvas').appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.add(
new THREE.Mesh(
new THREE.SphereGeometry(1),
new THREE.MeshBasicMaterial({color:'red'})
)
);
scene.background = new THREE.Color('yellow');
const camera = new THREE.PerspectiveCamera(45, 2, .1, 10);
camera.position.z = 2;
renderer.render(scene, camera);
#gameCanvas {
position: relative;
}
#insideText {
position: absolute;
left: 20px;
top: 20px;
}
<h1>some text</h1>
<div id='gameCanvas'>
<div id="insideText">First trial</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js"></script>

Random cutouts with HTML5 Canvas

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>

HTML5 - Display Typed Text from Textarea on Image

I want to display the typed text ( If a person types text in a textarea the text should be immediately visible On an image) on an image. I have developed following code but it`s not showing anything on image.. sorry i am a newbie in HTML5, please advise
<script type="text/javascript">
function test(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.onload = function(){
context.drawImage(imageObj, 10, 10);
context.font = "40pt Calibri";
context.fillText("My TEXT!", 20, 20);
};
imageObj.src = "smallimage.jpg";
};
</script>
</head>
<body>
<textarea onchange="test();" id="txtContents"></textarea>
<img src="smallimage.jpg" id="myCanvas">
First, your "img" tag should be a "canvas" tag. Also, with the way you have it currently, The image is reloaded every time a user types in the text area. I would recommend laying the canvas directly on top of the image and then just clearing the canvas and redrawing the text onchange(). Try something like this:
<script type="text/javascript">
function changeText(textarea){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var text = textarea.value;
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillText(text, 20, 20);
}
</script>
</head>
<body>
<textarea onkeyup="changeText(this);" id="txtContents"></textarea>
<div class="outer">
<img src="smallimage.jpg" class="box" id="myImage" />
<canvas class="box" id="myCanvas" width="100" height="100"></canvas>
</div>
</body>
CSS:
.outer{
position: relative;
}
.box {
width: 100px;
height: 100px;
}
#myImage {
}
#myCanvas {
position: absolute;
top: 0px;
left: 0px;
}
Check out: How to best overlay a canvas on an image? for laying the canvas directly on top of the image. The accepted answer has a fiddle in the comments that shows how to do it.

Canvas 3D drawing using both 2D and 3D context

Since the webgl/opengl doesn't support text drawing, so it possible to draw 3D object using 3D context and text drawing using 2D context ?
No, unfortunately not.
The HTML 5 spec says that if you call getContext on a canvas element that is already in a different context mode and the two contexts are not compatible then return null.
Unfortunately "webgl" and "2d" canvases are not compatible and thus you will get null:
var canvas = document.getElementById('my-canvas');
var webgl = canvas.getContext("webgl"); // Get a 3D webgl context, returns a context
var twod = canvas.getContext("2d"); // Get a 2D context, returns null
As stated, you cannot do this.
However you can put one canvas on top of another and draw to them separately. I've done this before and it can work out quite well.
Create the text as a texture using canvas 2D, then render it in 3D. See here for a tutorial.
What I've been doing, whether I just need troubleshooting feedback or 2D text content on a 3D canvas, is just use CSS to put some HTML elements on top of the canvas.
You can make a canvas and a group of text fields share the same space, and ensure that the text fields are on top as follows:
HTML:
<div id="container">
<canvas id="canvas"></canvas>
<div id="controlsContainer">
<label>Mouse Coordinates</label>
<div>
<label for="xPos">X</label>
<span id="xPos"></span>
</div>
<div>
<label for="yPos">Y</label>
<span id="yPos"></span>
</div>
</div>
</div>
CSS:
canvas {
margin: 0px;
position: relative;
top: 0px;
left: 0px;
width: 100%;
}
#container {
position: relative;
}
#controlsContainer {
position: absolute;
left: 10px;
top: 10px;
z-index: 3;
}
#controlsContainer div {
padding-left: 8px;
}
#controlsContainer label {
color: white;
z-index: 4;
}
#controlsContainer span {
color: white;
z-index: 4;
}
The z-index will ensure which elements are in front, and position: relative for the container and position: absolute, in coordination with the top and left for the controls will ensure that they share the same space.
I have been having very good luck with this, and the troubleshooting feedback is invaluable.
An example of the Javascript (ES6 in this case) is:
let xPos = document.getElementById("xPos");
let yPos = document.getElementById("yPos");
let x = event.clientX - containerDiv.offsetLeft -parseInt(window.getComputedStyle(pageBody).getPropertyValue("margin-left"));
let y = event.clientY - containerDiv.offsetTop - parseInt(window.getComputedStyle(pageBody).getPropertyValue("margin-top"));
xPos.innerText = x;
yPos.innerText = y;
which I've placed in a mousemove handler.