diagonal image overlay via css/javascript - javascript

I want to create a div overlay, set at 5% opacity, which creates a diagonal bounding box around the first line of text in this image. It seems to me that if I have the x,y coordinates for the four corners I should be able to create the overlay but I cannot figure out what the proper syntax would be to mark out the div. Am I wrong in thinking this can be done, and if not can someone point me at some methods for doing so?

Instead of using a canvas and javascript for simple cases you can use instead the transform property of css divs. For example with
#diag {
background-color: rgba(255, 0, 255, 0.25);
width: 700px;
height: 60px;
position: absolute;
left: 100px;
top: 160px;
transform: rotate(2deg) skew(30deg)
}
you can get a div positioned on the first line of the text in the image that can be styled easily with CSS for borders and that can be used directly for events (hover, clicks).
If you need to specify 4 corners however just a single transform is not enough in general and you have to draw your overlay in a canvas placed over the image. This works because a canvas is by default transparent and only what you explicitly draw will be visible leaving the image untouched in other areas. For example using:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
ctx.beginPath();
ctx.moveTo(166, 282);
ctx.lineTo(855, 296);
ctx.lineTo(897, 351);
ctx.lineTo(212, 349);
ctx.closePath();
ctx.fillStyle = "rgba(0, 255, 0, 0.25)";
ctx.strokeStyle = "#0F0";
ctx.lineWidth = 4;
ctx.fill();
ctx.stroke();
I've highlighted the third row in green (fill command) also adding a border (stroke command).
http://jsfiddle.net/hr9afs4z/1/

Related

How to change the shape of the canvas itself?

I'm working on a project and I use createCapture(VIDEO); using p5js libraries, to get the video using my web camera. Then I store every image of that capture (from < video> element) and draw it in a canvas in the function draw().
I was wondering if it's possible the change the shape of the canvas(such as a mirror for example (oval or circle)).
Again, notice that I don't want to crop the image but the canvas itself.
Here is some code:
function setup(){
canvas = createCanvas(640, 480); //480p
canvas.parent('editedCanvas-container');
originalCapture = createCapture(VIDEO);
originalCapture.parent('originalVideo-container');
originalCapture.size(640, 480); //480p
}
function draw(){
frame = image(originalCapture, 0, 0, width, height);
}
If somebody has a clue please let me know.
You can change the shape of your canvas tag by applying css rules,
So try this css code
#canvasObject {
border: 2px solid black;
width: 200px;
height: 150px;
border-radius: 100px / 50px;
}
<canvas id="canvasObject">
</canvas>
For more info about how to achieve shapes in css, please refer this amazing post for css-tricks

Replace a color on canvas

I'm using html5 canvas to make a game. I made a spritefont system to be able to draw text from a texture. Namely
.
Now I'd like to be able to change the white part of the text to any color I want. My guess is that I'll need to render the texture to a temporary canvas change the color and get the new texture and draw that instead.
However, I don't know how I can replace a color using the canvas's functions.
And I don't even know if this is the best way to do this. What should I do?
Since your spritefont is monochrome, you can use CanvasRenderingContext2D's 'multiply' globalCompositeOperation to apply color to the white part. But multiplying by a solid rectangle of color will wipe out the transparency, so you'll need to redraw the transparent parts with 'destination-atop'.
const FONT_COLOR = '#39f';
// Load up your spritefont
const spritefont = new Image();
spritefont.src = 'https://i.stack.imgur.com/mDvum.png';
// While waiting for the image to load,
// create a canvas to do the coloring work on
const fontCanvas = document.createElement('canvas');
const fontContext = fontCanvas.getContext('2d');
// Once the spritefont is loaded,
spritefont.addEventListener('load', function () {
// Resize the canvas to match the image's dimensions
fontCanvas.width = spritefont.width;
fontCanvas.height = spritefont.height;
// Draw your image on the canvas with a black background
// Without the background, you'll get tinting at the partially-transparent edges
fontContext.fillStyle = 'black';
fontContext.fillRect(0, 0, fontCanvas.width, fontCanvas.height);
fontContext.drawImage(spritefont, 0, 0);
// Multiply by the font color
// white * color = color, black * color = black
fontContext.globalCompositeOperation = 'multiply';
fontContext.fillStyle = FONT_COLOR;
fontContext.fillRect(0, 0, fontCanvas.width, fontCanvas.height);
// Restore the transparency
fontContext.globalCompositeOperation = 'destination-atop';
fontContext.drawImage(spritefont, 0, 0);
});
// Display the canvas in the snippet
document.body.append(fontCanvas);
/* just to prove that alpha is preserved */
canvas {background:0 0/32px 32px linear-gradient(45deg,#ccc 25%,transparent 25%,transparent 75%,#ccc 75%,#ccc),16px 16px/32px 32px linear-gradient(45deg,#ccc 25%,#999 25%,#999 75%,#ccc 75%,#ccc);}
If you plan to put the color-changing functionality in a function and reuse the canvas (which you should), make sure to set the context's globalCompositeOperation back to the default, 'source-over'.
HTML5 canvases follows draw and forget strategy. If you want any change (be it font color or change of shapes or text or lines etc) in what had been drawn earlier, you need to re-draw everything.
Mostly upto to my use of canvases, the whole re-drawing process is pretty fast and works without any lag or delay.
EDIT
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '20pt Verdana';
context.fillText('Some text', 50, 50);
context.strokeText('Some text', 50, 50);
context.fill();
context.stroke();

Move Section of Canvas to Other Canvas

I have two canvases, let's say Canvas A and Canvas B. The user uploads a file and it gets put on Canvas A, which I already have done. Once that happens, I want to start copying sections of Canvas A to Canvas B.
I have tried doing this
source = a.getContext('2d');
b.drawImage(source, 0, 0, source.width, source.height);
but that copies the whole thing. So my question is, how do I copy a part of Canvas A to Canvas B.
Edit:
I have also tried...
var imgData=atx.getImageData(10,10,20,20);
btx.putImageData(imgData, 0, 0);
but that just copies the imgData back onto Canvas A at (0, 0).
To start with, b.drawImage takes a CanvasImageSource as its first argument, not a Context. Pass your entire HTMLCanvasElement in there.
drawImage takes nine arguments, and you're gonna need all of them. If you only use five, it's assumed that you're taking the entire source image and drawing it at your destination. The full signature is
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
sx, sy, sw, and sh define the rectangle you're copying from your source. dx, dy, dw, and dh define the rectangle you're drawing in at your destination. Note that sw and sh don't have to match up with dw and dh. If the source and destination rectangles don't have the same size, the copied image will be squashed or stretched to fit the destination rectangle.
I've made a snippet that lets you play around with drawImage to see what it's doing. It works best when you view it as a full page:
const srcCanvas = document.querySelector('#source');
const srcContext = srcCanvas.getContext('2d');
const destContext = document.querySelector('#destination')
.getContext('2d');
// The overlay canvas is where we draw the red rectangle. It's
// positioned directly on top of the source canvas.
const overlay = document.querySelector('#overlay')
.getContext('2d');
overlay.fillStyle = 'rgba(255, 0, 0, 0.3)';
overlay.strokeStyle = 'red';
const inputs = Array.from(
document.querySelectorAll('input[type="number"]')
);
const lockScale = document.querySelector('#lockScale');
lockScale.addEventListener('change', () => {
inputs[6].disabled = lockScale.checked;
inputs[7].disabled = lockScale.checked;
if (lockScale.checked) update();
});
// Grab an image and draw it on the source canvas...
fetch('https://picsum.photos/320/240/?image=451')
.then(res => res.blob())
.then(createImageBitmap)
.then(bitmap => {
srcContext.drawImage(bitmap, 0, 0);
// ...and only then start watching for changes in the input boxes.
// There's no point in spending cycles copying an empty canvas.
inputs.forEach(i => {
i.addEventListener('input', update);
});
update();
});
function update() {
if (lockScale.checked) {
inputs[6].value = inputs[2].value;
inputs[7].value = inputs[3].value;
}
const values = inputs.map(i => Number(i.value));
destContext.clearRect(0, 0, 320, 240);
overlay.clearRect(0, 0, 320, 240);
overlay.beginPath();
overlay.rect(
// These adjustments move the overlay path off the boundary
// between pixels so the rectangle border is a crisp 1px line.
values[0] + 0.5,
values[1] + 0.5,
// JavaScript uses half-open intervals, which makes sense for
// code. But for a visualization of graphics work, fully-
// closed intervals are preferable. These adjustments make the
// overlay rectangle exactly cover the pixels that will be
// copied.
values[2] - 1,
values[3] - 1
);
overlay.fill();
overlay.stroke();
// The real drawing code of this snippet doesn't look like the
// code you would actually use. We call apply() on drawImage()
// so we can pass in the entire values array without listing out
// every element.
destContext.drawImage.apply(
destContext, // We don't want to change what 'this' points to
[srcCanvas].concat(values));
// The spread operator provides a more elegant way of doing this:
// destContext.drawImage(srcCanvas, ...values);
// But it doesn't work with IE.
}
canvas {
height: 240px;
width: 320px;
position: absolute;
top: 0;
left: 0;
}
.canvasbox {
display: inline-block;
position: relative;
width: 320px;
height: 240px;
border: 1px solid black;
}
input[type="number"] {
font-family: monospace;
border: none;
background: silver;
color: black;
width: 3em;
}
input[disabled] {
color: silver;
background: grey;
}
code {
color: navy;
}
<div class="canvasbox">
<canvas id="source" width="320" height="240"></canvas>
<canvas id="overlay" width="320" height="240"></canvas>
</div>
<div class="canvasbox">
<canvas id="destination" width="320" height="240"></canvas>
</div>
<div>
<code>
destContext.drawImage(srcCanvas,
<input id="sx" type="number" value="180">,
<input id="sy" type="number" value="100">,
<input id="sw" type="number" value="40">,
<input id="sh" type="number" value="50">,
<input id="dx" type="number" value="10">,
<input id="dy" type="number" value="10">,
<input id="dw" type="number" value="40">,
<input id="dh" type="number" value="50">);
</code>
</div>
<div>
<label>
<input id="lockScale" type="checkbox">Lock scale
</label>
</div>

Is there any way to make an html5 canvas element resizeable?

Is there a native solution that provides a handle in the corner of my HTML5 canvas similar to that in a default <textarea> element.
<textarea>resizeable</textarea>
I assume this will clear the canvas and will require a redraw as this is the case when resizing the canvas programmatically with canvas.width and canvas.height.
I looked around and found nothing, but wanted to check before rolling my own. If anyone is sure that there is no "easy" way, then that is a perfectly acceptable answer. Thanks!
The best I could come up with was use jQueryUI Resizable like so
jsFiddle : https://jsfiddle.net/n24dbaw9/
Html
<div class="resizable">
<canvas id="myCanvas"></canvas>
</div>
CSS
.resizable{
width: 400px;
height: 400px;
}
#myCanvas{
width: 100%;
height: 100%;
}
Javascript
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#777";
$(function() {
$(".resizable").resizable();
});
setInterval(function(){ ctx.fillRect(0, 0, 400, 400); }, 3);
Basically I have styled the canvas to fit inside of the "resizble" div, which is set to 400 by 400 at default. The canvas has a style which is 100% width and height so when the user resizes the "resizble" div the canvas will then just stretch out.
You will want to put the canvas into a JavaScript draw() function:
function draw() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
}
and your body element in css should have height and width set to 100%

How to draw a background image on an HTML5 canvas

I'm working on my first HTML5 Canvas game. I am trying to put in a background image, and I don't know how to do it. The game will change backgrounds throughout levels, but I think I understand how to make that happen. However, if I just try to draw an image, then it appears above my title text. Any ideas how to fix this? I don't think the CSS method will work, because the background will change. Here is my code:
<!DOCTYPE html>
<html>
<head>
<title>How Well Do You Know Your Swedish?</title>
</head>
<body>
<canvas width="640" height="480" id="game" style="display: block; margin-left: auto; margin-right: auto; border: 1px solid black;" Your Browser is not compatible with this game. We recommend Google Chrome, Mozilla Firefox, or Opera.></canvas>
<script>
var game_canvas = document.getElementById("game");
var game_context = game_canvas.getContext("2d");
var swedishflagbg = new Image();
swedishflagbg.src = "resources/images/swedishflagbg.png";
swedishflagbg.onload = function() {
game_context.drawImage(swedishflagbg, 0, 0);
}
game_context.fillStyle = "#000000";
game_context.font = "35px Ubuntu";
game_context.textAlign = "center";
game_context.textBaseline = "top";
game_context.fillText("How Well Do You Know Your Swedish?", 320, 0);
</script>
</body>
</html>
I am new to JavaScript, and even newer to the HTML5 Canvas.
Extending from comment:
The "why":
Because the background image is drawn in an onload event, which will happen "later", while text is drawn immediately.
So the text is drawn first, and then sometimes later the image is drawn, thus causing the text to be covered.
The "how":
Depending on how "dynamic" the background image is, you can consider:
use CSS background-image on cancas/canvas container, and use className/classList to switch between different backgrounds;
put an <img> tag underneath the canvas, and change its src property;
use an additional "background" canvas underneath the current one, so you can draw the game content in current one, and draw the (probably not frequently-updated) background in the new one.
Credit of idea 1 and 2 goes to #markE :)
First things:
Check the size of your image. It should be equivalent to the size of the canvas.
context.drawImage can also take width and height parameter for the image.
Syntax: context.drawImage(img, x, y, width, height);
After editing, it should look like this
let game_canvas = document.getElementById("game");
let game_context = game_canvas.getContext("2d");
let swedishflagbg = new Image();
swedishflagbg.src = "resources/images/swedishflagbg.png";
swedishflagbg.onload = function() {
game_context.drawImage(swedishflagbg, 0, 0, game_canvas.width, game_canvas.height);
}
game_context.fillStyle="#000000";
game_context.font="35px Ubuntu";
game_context.textAlign="center";
game_context.textBaseline="top";
game_context.fillText("How Well Do You Know Your Swedish?", 320, 0);
To anyone who is still facing the problem of background image overlaying text (Image above text), I thought "why not drawing text inside onload function after loading bg image!?"
And it worked!! The browser (Or whatever) loads image first and load my text above image.
<canvas width="534" height="104" id="game" style="display: block; margin-left: auto; margin-right: auto; border: 1px solid black;" Your Browser is not compatible with this game. We recommend Google Chrome, Mozilla Firefox, or Opera.></canvas>
<script>
let game_canvas = document.getElementById("game");
let game_context = game_canvas.getContext("2d");
let swedishflagbg = new Image();
swedishflagbg.src = "./img/logo1.png";
swedishflagbg.onload = function() {
game_context.drawImage(swedishflagbg, 0, 0, game_canvas.width, game_canvas.height);
game_context.fillStyle = "#000000";
game_context.font = "35px Ubuntu";
game_context.textAlign = "center";
game_context.textBaseline = "top";
game_context.fillText("How Well Do You Know Your Swedish?", 320, 0);
}
</script>

Categories

Resources