Html canvas, pixel manipulation and alpha channel - html
In html canvas, what I want to achieve is a white noise effect on a picture. So I get the picture, get its ImageData, modify it's alpha and draw it back.
var bat = new Image();
bat.src = "data:image/png;base64,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"
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 250;
canvas.height = 250;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(bat, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i] != 0 || data[i + 1] != 0 || data[i + 2] != 0) {
data[i + 3] = Math.floor(Math.random() * 255);
}
}
ctx.putImageData(imageData, 0, 0);
requestAnimationFrame(animate);
}
animate();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bat</title>
<link rel="stylesheet" href="style.css" />
<style>
#main {
display: flex;
flex-direction: row;
}
#canvas {
border: 1px solid black;
width: 150px;
height: 150px;
}
</style>
</head>
<body>
<div id="main">
<canvas id="canvas"></canvas>
<br />
</div>
<script src="script.js"></script>
</body>
</html>
The result is what I need. But the issue is that when you use putImageData, even if the alpha is 0, it won't be transparent.
So I use a temporary canvas, draw the picture on it, modify it and then draw it back on the canvas.
var bat = new Image();
bat.src = "data:image/png;base64,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";
var canvas2 = document.getElementById('canvas2');
var ctx2 = canvas2.getContext('2d');
var tempCanvas = document.createElement('canvas');
var tempContext = tempCanvas.getContext('2d');
canvas2.width = 250;
canvas2.height = 250;
tempCanvas.width = 250;
tempCanvas.height = 250;
var img = new Image();
var alpha = 0;
function animate2() {
alpha += 0.1;
ctx2.clearRect(0, 0, canvas.width, canvas.height);
ctx2.fillStyle = 'blue';
ctx2.fillRect(0, 0, 250, 250);
tempContext.drawImage(bat, 0, 0);
var imageData = tempContext.getImageData(
0,
0,
tempCanvas.width,
tempCanvas.height
);
var data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i] != 0 || data[i + 1] != 0 || data[i + 2] != 0) {
//data[i + 3] = Math.floor(Math.random() * 255);
data[i + 3] = 123;
//data[i + 3] = alpha;
}
}
tempContext.putImageData(imageData, 0, 0);
img.src = tempCanvas.toDataURL('image/png');
ctx2.drawImage(img, 0, 0);
requestAnimationFrame(animate2);
}
animate2();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bat</title>
<link rel="stylesheet" href="style.css" />
<style>
#main {
display: flex;
flex-direction: row;
}
#canvas2 {
border: 1px solid black;
width: 150px;
height: 150px;
}
</style>
</head>
<body>
<div id="main">
<canvas id="canvas"></canvas>
<br />
<canvas id="canvas2"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>
But whenever I want to change the alpha randomly with:
data[i + 3] = Math.floor(Math.random() * 255);
The picture won't display. And if I want to update the alpha other time with:
var alpha = 0;
alpha += 0.1
data[i + 3] = alpha;
The picture flickers...
What is the correct way to get my "white noise" picture that would be transparent so I can see the background through it?
Here is a link of a stackblitz with the demo in it.
First, don't call getImageData every frame. All you need is to know where the black pixels are in the image, these won't change so you can keep the same ImageData object all along, avoid slow read-backs from the GPU.
Then, you can drawImage() a canvas directly. No need to go through a new Image with a toDataURL() which will load your image async and indeed make your animation flicker.
So this would give:
var bat = new Image();
bat.src = "data:image/png;base64,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";
var canvas2 = document.getElementById('canvas2');
var ctx2 = canvas2.getContext('2d');
var tempCanvas = document.createElement('canvas');
var tempContext = tempCanvas.getContext('2d');
canvas2.width = 250;
canvas2.height = 250;
tempCanvas.width = 250;
tempCanvas.height = 250;
// store the ImageData in a way it's accessible at every frame
var imageData;
bat.onload = (evt) => { // always wait for the assets to load
ctx2.drawImage(bat, 0, 0);
imageData = ctx2.getImageData(0, 0, 250, 250);
animate2();
}
var alpha = 0;
function animate2() {
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
ctx2.fillStyle = 'blue';
ctx2.fillRect(0, 0, 250, 250);
var data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i] != 0 || data[i + 1] != 0 || data[i + 2] != 0) {
data[i + 3] = Math.floor(Math.random() * 255);
}
}
tempContext.putImageData(imageData, 0, 0);
// drawImage the tempCanvas directly
ctx2.drawImage(tempCanvas, 0, 0);
requestAnimationFrame(animate2);
}
#main {
display: flex;
flex-direction: row;
}
#canvas2 {
border: 1px solid black;
width: 150px;
height: 150px;
}
<div id="main">
<canvas id="canvas2"></canvas>
</div>
But you don't even need a second canvas here, you can draw "behind" the current drawing on a canvas thanks to the "destination-over" compositing mode. You can even use more compositing operations to clip that background so that only the image is "colored":
var bat = new Image();
bat.src = "data:image/png;base64,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";
var canvas2 = document.getElementById('canvas2');
var ctx2 = canvas2.getContext('2d');
canvas2.width = 250;
canvas2.height = 250;
// store the ImageData in a way it's accessible at every frame
var imageData;
bat.onload = (evt) => { // always wait for the assets to load
ctx2.drawImage(bat, 0, 0);
imageData = ctx2.getImageData(0, 0, 250, 250);
animate2();
}
function animate2() {
var data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
if (data[i] != 0 || data[i + 1] != 0 || data[i + 2] != 0) {
data[i + 3] = Math.floor(Math.random() * 255);
}
}
ctx2.putImageData(imageData, 0, 0);
ctx2.globalCompositeOperation = "destination-over"; // draw behind
ctx2.fillStyle = 'blue';
ctx2.fillRect(0, 0, 250, 250);
ctx2.globalCompositeOperation = "destination-in"; // keep only where new pixels are opaque
ctx2.drawImage(bat, 0, 0);
ctx2.globalCompositeOperation = "source-over"; // default
requestAnimationFrame(animate2);
}
#main {
display: flex;
flex-direction: row;
}
#canvas2 {
border: 1px solid black;
width: 150px;
height: 150px;
background: yellow
}
<div id="main">
<canvas id="canvas2"></canvas>
</div>
Related
Aligning SVG Clip Path on top of image
EDIT 1: Quick codepen of my current issue: https://codepen.io/zuffdaddy/pen/QWGewKr See how the clip path is massive while the image is small? How do align those two? Original: Intro: I'm making an Attack Disc for a submarine simulator game. The disc has multiple circular rings that all rotate and so far I have that part complete, but there's some overlapping transparent plastic parts that sit on top the rings and rotate as well. Problem: The problem is the plastic pieces that rotate on top are complex shapes (image of the shape here). The user needs to be able to click around them to manipulate the rings beneath them but also be able to click on them to rotate them as well. SVG Clipping paths seem to be the way to go but I cannot get the svg clip path to align with the image. Please ignore the JS, it's a temporary rotating script I pulled from another question here and will be rewritten towards finalization. /////////////////////////////// // ------- rotate -------- // /////////////////////////////// (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('attack_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('course_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('aob_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('bearing_lead_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); html { height: 100%; overflow: hidden; } body { background: #1c1c1c; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; } .wrapper { height: 100%; max-height: 960px; width: 100%; max-width: 960px; position: relative; margin: auto; } #attack_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/1.png'); background-size: contain; background-repeat: no-repeat; background-position: center; width: 30vw; max-width: 1124px; height: 30vw; max-height: 1124px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform-origin: 50% 50%; border-radius: 50%; } #course_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/2.png'); background-size: contain; background-repeat: no-repeat; background-position: center; width: 23vw; max-width: 868px; height: 23vw; max-height: 868px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform-origin: 50% 50%; border-radius: 50%; } #aob_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/3.png'); background-size: contain; background-repeat: no-repeat; background-position: center; width: 15.5vw; max-width: 592px; height: 15.5vw; max-height: 592px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform-origin: 50% 50%; border-radius: 50%; } #bearing_lead_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/4.png'); background-size: cover; background-repeat: no-repeat; background-position: center; width: 23.5vw; max-width: 884px; height: 23.5vw; max-height: 884px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; clip-path: url('#my-clip-path'); } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="wrapper"> <div id="attack_disc"></div> <div id="course_disc"></div> <div id="aob_disc"></div> <div id="bearing_lead_disc"> <svg class="svg"> <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.501,0 C0.556,0,0.555,0.04,0.555,0.04 C0.555,0.099,0.984,0.229,0.994,0.232 S1,0.243,0.999,0.251 C0.976,0.284,0.874,0.421,0.656,0.469 C0.656,0.469,0.648,0.47,0.647,0.474 C0.646,0.48,0.572,0.984,0.57,0.992 C0.569,0.996,0.569,0.999,0.561,0.999 C0.522,1,0.516,1,0.502,1 C0.487,1,0.482,1,0.443,0.999 C0.434,0.999,0.434,0.996,0.433,0.992 C0.432,0.984,0.358,0.48,0.357,0.474 C0.356,0.47,0.347,0.469,0.347,0.469 H0.347 C0.129,0.421,0.027,0.284,0.005,0.251 C0,0.243,0,0.236,0.01,0.232 S0.449,0.099,0.449,0.04 C0.449,0.04,0.447,0,0.502,0"></path></clipPath> </svg> </div> </div>
The problem appears to be that you extracted the shape and converted it to objectBoundingBox coordinates relative to itself. So the objectBoundingBox coords are no longer relative to your attack disc image. What you can do is apply a transform to the clip path to scale it down to where it should be. By trial and error I worked out an appropriate scaling that gets it to match the shape it is supposed to clip. transform="translate(0.5,1) scale(0.415,0.52) translate(-0.5,-1)" .svg { position: absolute; width: 0; height: 0; } .clipped { width: 884px; height: 884px; background: turquoise url(https://zuffdaddy.github.io/uboat-attack-disc/images/4.png); background-size: cover; -webkit-clip-path: url(#my-clip-path); clip-path: url(#my-clip-path); } <svg class="svg"> <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.501,0 C0.556,0,0.555,0.04,0.555,0.04 C0.555,0.099,0.984,0.229,0.994,0.232 S1,0.243,0.999,0.251 C0.976,0.284,0.874,0.421,0.656,0.469 C0.656,0.469,0.648,0.47,0.647,0.474 C0.646,0.48,0.572,0.984,0.57,0.992 C0.569,0.996,0.569,0.999,0.561,0.999 C0.522,1,0.516,1,0.502,1 C0.487,1,0.482,1,0.443,0.999 C0.434,0.999,0.434,0.996,0.433,0.992 C0.432,0.984,0.358,0.48,0.357,0.474 C0.356,0.47,0.347,0.469,0.347,0.469 H0.347 C0.129,0.421,0.027,0.284,0.005,0.251 C0,0.243,0,0.236,0.01,0.232 S0.449,0.099,0.449,0.04 C0.449,0.04,0.447,0,0.502,0" transform="translate(0.5,1) scale(0.415,0.52) translate(-0.5,-1)"></path></clipPath> </svg> <div class="clipped"></div>
Svg better to be inside div Svg better to be inside div so you have more control on the shape and it's also can be scale. First I fix your path 'd' with this site (https://aydos.com/svgedit/) Second I put the svg inside the div Third I order the svg with view box to suitable (with color red some transparent) like the background-image link in 'bearing_lead_disc' and use css pointer-events:none for ignore clicking on the div and then we can rotate the circles even we clicked on the shape. link: (https://codepen.io/omergal/pen/qBqzeQa) pic: /////////////////////////////// // ------- rotate -------- // /////////////////////////////// (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('attack_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('course_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('aob_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); (function() { var init, rotate, start, stop, active = false, angle = 0, rotation = 0, startAngle = 0, center = { x: 0, y: 0 }, R2D = 180 / Math.PI, rot = document.getElementById('bearing_lead_disc'); init = function() { rot.addEventListener("mousedown", start, false); $(document).bind('mousemove', function(event) { if (active === true) { event.preventDefault(); rotate(event); } }); $(document).bind('mouseup', function(event) { event.preventDefault(); stop(event); }); }; start = function(e) { e.preventDefault(); var bb = this.getBoundingClientRect(), t = bb.top, l = bb.left, h = bb.height, w = bb.width, x, y; center = { x: l + (w / 2), y: t + (h / 2) }; x = e.clientX - center.x; y = e.clientY - center.y; startAngle = R2D * Math.atan2(y, x); return active = true; }; rotate = function(e) { e.preventDefault(); var x = e.clientX - center.x, y = e.clientY - center.y, d = R2D * Math.atan2(y, x); rotation = d - startAngle; return rot.style.webkitTransform = "rotate(" + (angle + rotation) + "deg)"; }; stop = function() { angle += rotation; return active = false; }; init(); }).call(this); html { height: 100%; overflow: hidden; } body { background: #1c1c1c; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; } .wrapper { height: 100%; max-height: 960px; width: 100%; max-width: 960px; position: relative; margin: auto; } #attack_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/1.png'); background-size: contain; background-repeat: no-repeat; background-position: center; width: 30vw; max-width: 1124px; height: 30vw; max-height: 1124px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform-origin:50% 50%; border-radius:50%; } #course_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/2.png'); background-size: contain; background-repeat: no-repeat; background-position: center; width: 23vw; max-width: 868px; height: 23vw; max-height: 868px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform-origin:50% 50%; border-radius:50%; } #aob_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/3.png'); background-size: contain; background-repeat: no-repeat; background-position: center; width: 15.5vw; max-width: 592px; height: 15.5vw; max-height: 592px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform-origin:50% 50%; border-radius:50%; } #bearing_lead_disc { background-image: url('https://zuffdaddy.github.io/uboat-attack-disc/images/4.png'); /* background-color: red; */ background-size: contain; background-repeat: no-repeat; background-position: center; width: 23.5vw; max-width: 884px; height: 23.5vw; max-height: 884px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0; clip-path: url('#myPath'); } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="wrapper"> <div id="attack_disc"></div> <div id="course_disc"></div> <div id="aob_disc"></div> <div id="bearing_lead_disc" style="pointer-events:none;"> <svg viewBox="0 0 512 512" style="width:100%; height:100%;"> <path style="pointer-events:all;" fill="#ff00004d" d="M255.77 26.76c20 0 19.5 18.5 19.5 18.5 0 27 155.5 86.5 159 88s3.61 5.03 1.78 8.5c-8.07 15.27-45.11 77.9-124.18 99.85 0 0-3.05.81-3.32 2.67-.38 2.6-27.27 233.45-27.88 237.47-.27 1.76-.27 2.84-3.35 2.97-14.18.56-16.1.53-21.37.53s-7.19.03-21.37-.53c-3.08-.12-3.09-1.2-3.35-2.97-.61-4.03-27.5-234.88-27.88-237.47-.27-1.86-3.32-2.69-3.32-2.69-79.01-21.98-116.01-84.57-124.08-99.84-1.83-3.47-1.72-7 1.78-8.5s159-61 159-88c0 0-.5-18.5 19.5-18.5" /> </svg> </div> </div>
Fill textstroke() with white in canvas while keeping the black outline
Everything is woorking in this script. the outline of text is black which is fine. Just the inside needs to be filled with white keeping the same background image. <body> <canvas id="c" width="800" height="800"></canvas> <script> var c = document.querySelector("#c"); var ctx = c.getContext("2d"); var image = new Image(); image.onload = function(){ console.log("Loaded image"); // do something else ctx.drawImage(image, 0, 0, c.width, c.height); ctx.fillStyle = "rgb(0,0,0)"; ctx.strokeStyle = "Black"; ctx.fill(); ctx.font = "bold 36pt impact"; ctx.lineWidth = 3; ctx.strokeText("Hello Hello!", 50, 50); } image.src = "http://i.stack.imgur.com/9HgIv.png"; //ctx.strokeText("Hello Hello!", 50, 50); </script> </body>
Like this...? var c = document.querySelector("#c"); var ctx = c.getContext("2d"); var image = new Image(); image.onload = function(){ console.log("Loaded image"); // do something else ctx.drawImage(image, 0, 0, c.width, c.height); ctx.fillStyle = "white"; ctx.strokeStyle = "Black"; ctx.font = "bold 36pt impact"; ctx.lineWidth = 3; ctx.fillText("Hello Hello!", 50, 50); ctx.strokeText("Hello Hello!", 50, 50); } image.src = "http://i.stack.imgur.com/9HgIv.png"; body{ background-color: ivory; } #canvas{border:1px solid red; margin:0 auto; } <canvas id="c" width=300 height=300></canvas>
Inverse Canvas Colors
This code produces a mathematical object: a white geometric shape that builds upon a white background. I can change the background color in the canvas tag, and the color of the lines that build the shape. The problem is a black square remains even when I change the canvas color. My goal is just to simply invert the colors, from a black background with a white shape to a black shape with a white background. var canvas; var ctx; var canvasWidth = 600; var canvasHeight = 600; var circleR = 300; var timeout = 0; var often = 15; function init() { if (location.hash) often = 5; canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); drawLines(); } function drawLines() { ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.translate(canvasWidth / 2, canvasHeight / 2); for (var i = 0; i < 25; i++) { for (var a = -45; a <= 45; a += often) { setTimeout("drawTimeout(" + a + ");", 100 * timeout); timeout++; } } } function drawTimeout(a) { ctx.beginPath(); ctx.moveTo(0, circleR); var radians = Math.PI / 180 * a; var x = (circleR * Math.sin(radians)) / Math.sin(Math.PI / 2 - radians); ctx.lineTo(x, 0); if (Math.abs(a) == 45) { ctx.strokeStyle = "rgb(255,255,255)"; ctx.lineWidth = 1; } else if (a == 0) { ctx.strokeStyle = "rgb(200,200,200)"; ctx.lineWidth = 0.5; } else { ctx.strokeStyle = "rgb(110,110,110)"; ctx.lineWidth = 0.2; } ctx.stroke(); ctx.rotate((Math.PI / 180) * 15); } function redirect() { if (window.location.hash) window.location.href = ''; else window.location.href = '#more'; window.location.reload(true); } init(); body { margin: 0; background-color: black; } canvas { display: block; margin: 10px auto; background-color: black; } <canvas id="canvas" width="600" height="600"></canvas>
Here is a white on black version of your animation, didn't made so much changes, just the stroke colors and css. var canvas; var ctx; var canvasWidth = 600; var canvasHeight = 600; var circleR = 300; var timeout = 0; var often = 15; function init() { if (location.hash) often = 5; canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); ctx.fillStyle = "#FFF"; drawLines(); } function drawLines() { ctx.fillRect(0, 0, canvasWidth, canvasHeight); ctx.translate(canvasWidth / 2, canvasHeight / 2); for (var i = 0; i < 25; i++) { for (var a = -45; a <= 45; a += often) { setTimeout("drawTimeout(" + a + ");", 100 * timeout); timeout++; } } } function drawTimeout(a) { ctx.beginPath(); ctx.moveTo(0, circleR); var radians = Math.PI / 180 * a; var x = (circleR * Math.sin(radians)) / Math.sin(Math.PI / 2 - radians); ctx.lineTo(x, 0); // store a variable for our color, since you only use shades of grey; var c; if (Math.abs(a) == 45) { c = 0; // 255-255 ctx.strokeStyle = "rgb("+c+","+c+","+c+")"; ctx.lineWidth = 1; } else if (a == 0) { c = 55; // 255-200 ctx.strokeStyle = "rgb("+c+","+c+","+c+")"; ctx.lineWidth = 0.5; } else { c = 145; // 255-110 ctx.strokeStyle = "rgb("+c+","+c+","+c+")"; ctx.lineWidth = 0.2; } ctx.stroke(); ctx.rotate((Math.PI / 180) * 15); } function redirect() { if (window.location.hash) window.location.href = ''; else window.location.href = '#more'; window.location.reload(true); } init(); body { margin: 0; background-color: black; } canvas { display: block; margin: 10px auto; background-color: white; } <canvas id="canvas" width="600" height="600"></canvas>
Pulsating color change on svg image
I came across this awesome design today: http://codepen.io/tmrDevelops/pen/jPLpLJ I really like the pulsating color change. On my website I have an .svg logo that I would like to change color like that when I hover over the image. I would like the actual svg to change color, not the background or anything. I really don't need the on-click animation. Is this possible with css? I know I have the source right there in the codepen but this is a little above my skills. Note: It doesn't even have to be based on this code. As long as it looks sort of the same it's ok. HTML: <canvas id="canv"></canvas> <h4>Click For Random Squiggle</h4> CSS: #import url(http://fonts.googleapis.com/css?family=Poiret+One); body { width: 100%; margin: 0; overflow: hidden; cursor: pointer; background: hsla(0, 0%, 10%, 1); font-family: 'Poiret One', serif; } h4 { width: 100%; position: absolute; text-align: center; bottom: 0; left: 0; color: hsla(255, 255%, 255%, .5); font-size: 2em; letter-spacing: 15px; user-select: none; } JavaScript: window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })(); var max = 50; var rad = 200; var c, $, inc, p; var c = document.getElementById('canv'); var $ = c.getContext('2d'); var w = c.width = window.innerWidth; var h = c.height = window.innerHeight; var u = 0; var go = function() { upd(); draw(); } var upd = function() { for (var i = 0; i < max; i++) { if (i % 2 == 0) { p[i].upd(inc); } else { p[i].upd(0); } } } var draw = function() { u -= .5; $.clearRect(0, 0, c.width, c.height); $.fillStyle = 'hsla(0,0%,10%,1)'; $.fillRect(0, 0, w, h); var xp1 = (p[0].x + p[max - 1].x) / 2; var yp1 = (p[0].y + p[max - 1].y) / 2; /* first beginPath() set is a shadow mimic - a black underlay, which is not necessary but the canvas shadow attr kills the springiness in FF :/ so using this instead for a lil depth. */ $.beginPath(); $.strokeStyle = 'hsla(0,0%,5%,.35)'; $.lineWidth = 26; $.moveTo(xp1, yp1); for (var i = 0; i < max - 1; i++) { var xp = (p[i].x + p[i + 1].x) / 2; var yp = (p[i].y + p[i + 1].y) / 2; $.quadraticCurveTo(p[i].x - 2, p[i].y + 2, xp, yp); } $.quadraticCurveTo(p[i].x, p[i].y, xp1, yp1); $.closePath(); $.stroke(); //this one is the actual color circle. $.beginPath(); $.strokeStyle = 'hsla(' + u + ',100%, 50%,1)'; $.lineWidth = 20; $.moveTo(xp1, yp1); for (var i = 0; i < max - 1; i++) { var xp = (p[i].x + p[i + 1].x) / 2; var yp = (p[i].y + p[i + 1].y) / 2; $.quadraticCurveTo(p[i].x, p[i].y, xp, yp); } $.quadraticCurveTo(p[i].x, p[i].y, xp1, yp1); $.closePath(); $.stroke(); } var set = function() { var rot = 360 / max; p = []; for (var i = 0; i < max; i++) { var pt = new Pt(w / 2, h / 2); pt.radii = rot * i; pt.rad = rad; pt.ready(); p.push(pt); } } window.addEventListener('mousedown', function() { var rnd = (Math.random() * 410) + 10; inc = (inc == 0) ? rnd : 0; }, false); var ready = function(e) { inc = 0; set(); run(); } var run = function() { window.requestAnimFrame(run); go(); } var Pt = function(midX, midY) { this.acc = 5; this.chng = 1.35; this.midX = midX; this.midY = midY; this.vert = 0; this.x, this.y, this.rad, this.radii, this.dia; this.ready = function() { this.dia = this.rad; this.XY(); } this.upd = function(inc) { var r = this.dia + inc; this.rad = this.getRad(r, this.rad); this.XY(); } this.XY = function() { var cos = Math.cos(this.radii * (Math.PI / 180)) * this.rad; var sin = Math.sin(this.radii * (Math.PI / 180)) * this.rad; this.x = cos + this.midX; this.y = sin + this.midY; } this.getRad = function(mv, cur) { this.vert = (this.vert + ((mv - cur) / this.acc)) / this.chng; return this.vert + cur; } } window.addEventListener('resize', function() { c.width = w = window.innerWidth; c.height = h = window.innerHeight; set(); }, false); ready();
Like this? .hue { fill: red; } .hue:hover { animation: pulse 10s infinite; -webkit-animation: pulse 10s infinite; } #keyframes pulse { 0% { fill: #ff0000 } 17% { fill: #ffff00 } 33% { fill: #00ff00 } 50% { fill: #00ffff } 67% { fill: #0000ff } 83% { fill: #ff00ff } 100% { fill: #ff0000 } } #-webkit-keyframes pulse { 0% { fill: #ff0000 } 17% { fill: #ffff00 } 33% { fill: #00ff00 } 50% { fill: #00ffff } 67% { fill: #0000ff } 83% { fill: #ff00ff } 100% { fill: #ff0000 } } <svg> <circle cx="150" cy="75" r="70" class="hue"/> </svg> This should work in Firefox and Chrome.
CSS - how to create circle pie canvas like this?
I really like this element, but how to create it? I am not sure what's the correct designation of the element... Thank you very much.
This effect can be achieved by layering a couple arc()s: // bright blue full circle d.beginPath(); d.arc(50, 50, 50, 0, 2 * Math.PI, false); d.fillStyle = "#aaeeff"; d.fill(); // dark blue percentage circle d.beginPath(); d.moveTo(50, 50); d.arc(50, 50, 50, -0.5 * Math.PI, 0.78 * 2 * Math.PI - 0.5 * Math.PI, false); d.fillStyle = "#00aaff"; d.fill(); // white inner filler d.beginPath(); d.moveTo(50, 50); d.arc(50, 50, 25, 0, 2 * Math.PI, false); d.fillStyle = "#ffffff"; d.fill(); and finally rendering the text: d.moveTo(50, 50); d.fillStyle = "#606060"; d.font = "12pt sans-serif"; d.fillText("78%", 36, 56); Fiddle: http://jsfiddle.net/j6NVg/
Instead of using the <canvas> element, I have chosen to construct the pie chart relying on CSS and JS entirely. The HTML markup is as follow: <div class="pie" data-percent="78"> <div class="left"> <span></span> </div> <div class="right"> <span></span> </div> </div> The CSS is as follow. The trick is to split the circle into two halves (the nested .left and .right elements). The halves will have their overflowing content hidden, and contain nested <span> that we will manipulate with JS for rotation later. Add vendor prefixes when appropriate :) .pie { background-color: #eee; border-radius: 50%; width: 200px; height: 200px; overflow: hidden; position: relative; } .pie > div { float: left; width: 50%; height: 100%; position: relative; overflow: hidden; } .pie span { background-color: #4a7298; display: block; width: 100%; height: 100%; } .pie .left span { border-top-right-radius: 0; border-bottom-right-radius: 0; -webkit-transform-origin: 100% 50%; transform-origin: 100% 50%; } .pie .right span { border-top-left-radius: 0; border-bottom-left-radius: 0; -webkit-transform-origin: 0% 50%; transform-origin: 0% 50%; } .pie:before, .pie:after { border-radius: 50%; display: block; position: absolute; top: 50%; left: 50%; -webkit-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); } .pie:before { background-color: #fff; content: ""; width: 75%; height: 75%; z-index: 100; } .pie:after { content: attr(data-percent) "%"; z-index: 200; text-align: center; } I have used the following with jQuery: $(function() { $(".pie").each(function() { var percent = $(this).data("percent").slice(0,-1), // Removes '%' $left = $(this).find(".left span"), $right = $(this).find(".right span"), deg; if(percent<=50) { // Hide left $left.hide(); // Adjust right deg = 180 - (percent/100*360) $right.css({ "transform": "rotateZ(-"+deg+"deg)" }); } else { // Adjust left deg = 180 - ((percent-50)/100*360) $left.css({ "transform": "rotateZ(-"+deg+"deg)" }); } }); }); Here is the fiddle: http://jsfiddle.net/Aw5Rf/7/
Check the below links for more info (not an exact one.But you can get some idea). <!doctype html> <html> <head> <meta charset="UTF-8" /> <title>Canvas Test</title> </head> <body> <section> <div> <canvas id="canvas" width="400" height="300"> This text is displayed if your browser does not support HTML5 Canvas. </canvas> </div> <script type="text/javascript"> var myColor = ["#ECD078","#D95B43","#C02942","#542437","#53777A"]; var myData = [10,30,20,60,40]; function getTotal(){ var myTotal = 0; for (var j = 0; j < myData.length; j++) { myTotal += (typeof myData[j] == 'number') ? myData[j] : 0; } return myTotal; } function plotData() { var canvas; var ctx; var lastend = 0; var myTotal = getTotal(); canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < myData.length; i++) { ctx.fillStyle = myColor[i]; ctx.beginPath(); ctx.moveTo(200,150); ctx.arc(200,150,150,lastend,lastend+ (Math.PI*2*(myData[i]/myTotal)),false); ctx.lineTo(200,150); ctx.fill(); lastend += Math.PI*2*(myData[i]/myTotal); } } plotData(); </script> </section> </body> </html> For more info :Graphing Data in the HTML5 Canvas Element Simple Pie Charts Another Link : Pure CSS3 Pie Charts effect This is an online demo: http://jsbin.com/uFaSOwO/1/
First of all what you need can be done exactly using jQuery knob plugin. Still interested in a CSS Solution, than here's what I have done <div class="load_me"></div> .load_me { margin: 100px; height: 50px; width: 50px; border: 5px solid #f00; border-radius: 50%; border-top-color: transparent; } Demo Animating the Knob Credits If you want to prevent the mouse alteration, you can simply add readOnly $this.knob({ readOnly: true }); Demo
FIDDLE with ANIMATION Here's my approach: var ctx = canvas.getContext('2d'); /* * in canvas, 0 degrees angle is on the right edge of a circle, * while we want to start at the top edge of the circle. * We'll use this variable to compensate the difference. */ var relativeAngle = 270; function drawCanvas() { ctx.clearRect(0, 0, 90, 90); //light blue circle ctx.lineWidth = 20; ctx.strokeStyle = '#D8E8F7'; ctx.beginPath(); ctx.arc(45, 45, 35, 0, 2*Math.PI); ctx.stroke(); //dark blue circle ctx.strokeStyle = '#66ADF4'; ctx.beginPath(); //notice the angle conversion from degrees to radians in the 5th argument ctx.arc(45, 45, 35, 1.5*Math.PI, ((angle + relativeAngle) / 180) * Math.PI); ctx.stroke(); //text ctx.textBaseline = 'middle'; ctx.textAlign = 'center'; ctx.fillStyle = '#666'; ctx.font = 'bold 14px serif'; // angle conversion to percentage value ctx.fillText(parseInt(100 * angle / 360).toString() + '%', 45, 45); } var angle; function timeout() { angle = parseInt(360 * percent / 100); drawCanvas(); if (angle > 360) { document.getElementById('run').disabled = false; percent = 0; return; } percent++; setTimeout(timeout, 10); }; var percent = 0; /* START the ANIMATION */ timeout(); At the bottom of the code you'll find a self evaluating function timeout which calls the drawCanvas function every 10 miliseconds and increments the blue circle angle. I hope everything is clear here. If not, feel free to ask! Enjoy it!