Preserving part of a canvas - javascript

When drawing on a HTML5 canvas element, is it possible to leave part of it untouched? Can you take part of the image, and then redraw that part if its not directly possible?
The only solution I have thought of is to draw to a seprate, smaller canvas and then copy that over to the main canvas. Is this a feasible approach?
I wish to draw a game scene while preserving the ui. Unfortunately, the draw order is not known in advance.

I guess you're looking for .clip: http://jsfiddle.net/eGjak/122/.
ctx.rect(100, 50, 200, 100); // make a region
ctx.clip(); // constrain to that region
ctx.drawImage($("img").get(0), 0, 0); // draw image

Draw the UI on another canvas. You can layer canvas elements if need be.
HTML
<div id="gameframe">
<canvas id="game-ui"></canvas>
<canvas id="game"></canvas>
</div>
CSS
#gameFrame { position: relative; width: 800px; height: 800px;}
#game-ui { position: absolute; z-index: 10; bottom: 0; left; 0; height: 50px; width: 100%;}
#game { position: absolute; z-index: 5; height: 100%; width: 100%;}
Yields
-------------------------------------------------------
- -
- -
- -
- <canvas id="game"> -
- -
- -
- -
- -
-------------------------------------------------------
- <canvas id="game-ui"> -
-------------------------------------------------------

When creating Canvas games i've always layered the GUI on top of the game canvas.
#ui{position: fixed; margin-left: auto; margin-right: auto; z-index: 1000; width: 500; height: 500}
#game{position: fixed; margin-left: auto; margin-right: auto; z-index: 999}
<div id="ui"><!--UI elements--></div>
<canvas id="game" width="500" height="500"></canvas>
Obviously you can layer another canvas on top, or build the UI using html elements.

Related

Canvas takes up space of parent div

I've done a lot of searching, but I am unable to solve this problem I'm having.
I have a canvas nested in a div, with the intention of having the div serve as the background for the canvas, so that I can draw objects on it and whatnot.
When I run my code, the canvas appears side by side with the div, and I am unsure what to change to fix it.
// html
<body>
<div id="root">
<div id='board'>
<div>test</div>
<canvas></canvas>
</div>
</div>
</body>
// css
#board {
position: relative;
display: flex;
width: 640px;
height: 640px;
}
// js
let canvas = document.querySelector('canvas')
let ctx = canvas.getContext('2d')
canvas.width = canvas.offsetWidth
canvas.height = canvas.offsetHeight
Looked up similar questions on here with little success. Insight would be very appreciated!
You can add this styling for example, to center your canvas and then add more items as you need to the background div.
canvas {
background-color: green;
width: 200px;
height: 200px;
align-self: center;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
left: 50%;
}
I added an image of the result.

Apply CSS style to part of a canvas

I'd like to apply a specifc cursor png to only part of a canvas. I have this, which works fine for the whole canvas
.myClass {
cursor: url('../img/myCursor.png') 7 33, auto; /* img hotspot centred*/
}
But I'd like, for example, to apply it to only the left hand 50% of canvas (or say first 300px on x axis).
Is this possible ?
You can position 2 divs over the canvas and have a different cursor property for each one:
const c = document.querySelector('canvas').getContext('2d');
c.beginPath();
c.moveTo(200, 0);
c.lineTo(200, 400);
c.stroke();
/* draw vertical line down middle */
.container {
position: relative;
width: 400px;
}
canvas {
border: 1px solid;
}
.positioned {
position: absolute;
top: 0;
height: 100%;
width: 50%;
}
#left {
left: 0;
cursor: url('https://www.gravatar.com/avatar/0fdacb141bca7fa57c392b5f03872176?s=48&d=identicon&r=PG&f=1') 7 33, auto;
}
#right {
cursor: url('https://www.gravatar.com/avatar/0fdacb141bca7fa57c392b5f03872176') 7 33, auto;
right: 0px;
}
<div class="container">
<canvas height="400" width="400"></canvas>
<div class="positioned" id="left"></div>
<div class="positioned" id="right"></div>
</div>

How to convert this unrecognizable CSS feature into javascript?

I have this problem where I am trying to move a CSS image in correspondence to time but can not use it because it is in CSS. The feature is not the sun, but that yellowish half-circle animation that can be seen in this pen. I am trying to apply that half circle to a completely random shape.
For instance, if the shape is completely random and is on a white canvas and there is a random deformed circle in the middle, then how to fill that circle with the same animation as seen in this pen and how to convert that CSS to javascript or how to control the CSS, because it has to stop and move when certain values are set in.
I do not expect someone to do the whole thing, but rather maybe assist on where I should start when I need to use that yellowish feature as seen in that pen.
Thank you.
Here is the thing.
<div class="sunmoon">
<h2>Sun & Moon</h2>
<div class="sun-times">
<div class="sun-path">
<div class="sun-animation"></div>
</div>
<div class="sun-symbol-path"><span class="symbol">☀</span></div>
</div>
<div class="legend">
<div class="sunrise">05:30 AM</div>
<div class="sunset">8:04 PM</div>
</div>
<div class="clear"> </div>
</div>
<div class="controls">
<button class="start">Start</button>
<button class="reset">Reset</button>
</div>
#import "compass/css3";
$arc-diameter: 170px;
.sunmoon {
position: relative;
& > div {
margin-left: 10px
}
}
.sun-times {
margin-top: 40px;
width: 230px;
height: 60px;
border-bottom: 1px solid #999;
overflow-y: hidden;
.sun-path {
margin-left: 25px;
width: $arc-diameter;
height: $arc-diameter;
overflow: hidden;
border: 1px dashed #999;
border-radius: 50%;
}
.sun-symbol-path {
position: absolute;
color: yellow;
text-shadow: 0 0 5px black;
height: $arc-diameter / 2;
-webkit-transition: -webkit-transform 2s linear;
-webkit-transform-origin: 50% 100%;
-webkit-transform: rotateZ(-75deg);
left: ($arc-diameter / 2) + 25px;
bottom: 0;
.symbol {
position: relative;
font-size: 16px;
top: -8px;
}
}
.sun-animation {
width: 0px;
height: 150px;
background-color: rgba(255, 255, 0, 0.4);
-webkit-transition: width 2s linear;
transition: width 2s linear;
}
}
.legend {
position: absolute;
bottom: 1em;
& > div {
position: absolute;
font-size: 12px;
width: 80px;
}
.sunrise {
left: 15px;
}
.sunset {
left: 185px;
}
}
body {
background-image: url(foo);
background-color: #ccc;
font-family: Helvetica, Sans serif;
h2 {
font-size: 20px;
}
}
.controls {
margin-top: 50px;
}
$('.start').click(function () {
$('.sunmoon .sun-animation').css('width', '70%');
$('.sun-symbol-path').css('-webkit-transform', 'rotateZ(27deg)');
// TODO: mention that this isn't nice
// city.find('.sunmoon .sun-animation').css('-webkit-transform', 'scaleX(50)');
return false;
});
$('.reset').click(function () {
$('.sun-animation').css('width', '0%');
$('.sun-symbol-path').css('-webkit-transform', 'rotateZ(-75deg)');
return false;
});
You can achieve it creating a shape in Illustrator with the inside transparent and the outside in the color that you want, and setting another box (with a new color, in this case yellow, and the same width of the shape), underneath that shape (e.g. using z-index) with position:absolute and left:-100%, and onClick, start and stop the transition to right.
I'll recommend you to use GSAP TimeLineMax. It lets you play and stop the transition with its functions, e.g.:
//off course after document load.
let animation = new TimelineMax();
animation
.to(
".underneath-box", //box class
10, //seconds
{
left:"100%", //100% of the width
ease: Power4.easeInOut //ease effect.
});
animation.pause(); //To prevent start.
$('start-button').click(function(){ //on start button click
animation.play().timeScale(1); //start animation
});
$('reset-button').click(function(){ //on reset button click
animation.reverse().timeScale(2); //reverse the entire animation
});
I'm assuming that you know some Html, and css basics. Don't forget to create those divs and buttons with its classes. Cheers.
Well, I had some fun figuring this one out. Not sure that's what you wanted but it's what I've got. Plain JS.
var c1 = document.getElementById("canvas1");
var c2 = document.getElementById("canvas2");
var ctx = c1.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 90, 0, 2 * Math.PI);
ctx.lineWidth = 2;
ctx.stroke();
animateCanvas();
function animateCanvas(){
var w = 0;
var timer = setInterval(function(){
c2.width = w;
w += 1;
var ctx = c2.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 89, 0, 2 * Math.PI);
ctx.fillStyle = "#efba32";
ctx.fill();
if (w===200){clearInterval(timer)}
}, 20);
}
.canvases{
position: absolute;
top: 0;
left: 0;
}
<canvas id="canvas1" class="canvases" width="200" height="200"></canvas>
<canvas id="canvas2" class="canvases" width="200" height="200"></canvas>
The example you've attached uses two divs, and outer and an inner, to create this effect. The outer div has a border radius property to make it look like a half circle. The inner div is a normal rectangle with overflow set to hidden. So the script creates the optical illusion of wiping to the right by animating the width of the inner div going from 0% of the outer div to 70%. To make this illusion work with a polygon, you would need to use something like clip-path instead of border-radius.
Here is an example of an arbitrary polygon, that will wipe right with a different background color. HTML:
<div>
<div class="outer"><div class="inner"></div></div>
</div>
CSS:
.outer {
margin-left:200px;
background-color: lightgray;
width: 300px;
height: 100px;
display: block;
overflow: hidden;
-moz-clip-path: polygon(0px 0px, 300px 0px, 300px 300px);
-webkit-clip-path: polygon(0px 0px, 300px 0px, 300px 300px);
clip-path: polygon(0px 0px, 300px 0px, 300px 300px);
}
.inner {
background-color: red;
width :0;
height: 300px;
display: block;
}
jQuery:
$('.outer').click(function() {
$('.inner').animate({width:"150px"}, 1800)
});
Here is a working fiddle: https://jsfiddle.net/r93pocgt/
My implementation uses jQuery's animate to change the CSS property for width, when you click on the outer div. I've done my best to simplify it to make it clear what's doing what.

Using 100% does not make my canvas fill the window [duplicate]

This question already has answers here:
Getting wrong canvas height
(2 answers)
Closed 7 years ago.
I'm trying to make my canvas fill up the entire window. Setting the width and height to 100% isn't working at all. Instead, it's making it 100px by 100px. Why would this be happening, and how can I achieve my effect?
Here's a fiddle that basically shows my problem. Thank you!
https://jsfiddle.net/t04n6q9y/1/
<body height="100%" width="100%">
<canvas id="myCanvas" width="100%" height="100%"></canvas>
</body>
The width and height are attributes and don't support % they need to be absolute. If you give 100% width and height in CSS, your canvas will not scale to 100% instead it will be zoomed to 100%. I would suggest the following way to achieve 100% width and height:
You need to calculate width in javascript and then apply it, Fiddle
js:
var height = window.innerHeight;
var width = window.innerWidth;
var canvas = document.getElementById('myCanvas');
canvas.height = height;
Snippet:
var height = window.innerHeight;
var width = window.innerWidth;
var canvas = document.getElementById('myCanvas');
canvas.height = height;
canvas.width = width;
var context = canvas.getContext('2d');
context.fillStyle = "#FFFF00";
context.fillRect(0, 0, canvas.width, canvas.height);
body {
margin: 0px;
padding: 0px;
background-color: #00000F
}
canvas {
padding: 0;
margin: auto;
display: block;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<body>
<canvas id="myCanvas"></canvas>
</body>
You should be doing this with CSS rather than HTML tag attributes. By declaring a CSS class, you will be able to apply this same style to anything else you may want to fullscreen. It also separates the DOM logic from the styling logic.
Here's how I would do it:
HTML:
<canvas class="fullscreen"></canvas>
CSS:
canvas.fullscreen {
width: 100vw;
height: 100vh;
}
The "vw" and "vh" units represent percentage of View Width and View Height, respectively. Using these units will ensure your canvas fills the entire viewport regardless of the size of its parent elements.
All that needed to be done was for the canvas to have an element to expand in.
HTML:
<body>
<div id="canback">
<canvas id="myCanvas"></canvas>
</div>
</body>
CSS:
body {
margin: 0px;
padding: 0px;
background-color: #00000F
}
#canback {
height: 100%;
width: 100%;
margin: 0 auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#myCanvas {
background:#f4f4f4;
height:100%;
width: 100%;
padding: 0;
margin: 0 auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
Here is a Fiddle
I hope this helped. :D

Put overlay on document with transparent window

I would like to do something with my document which is quite unique (haven't seen it before) and thus maybe not even possible.
What I would like is to have a div which will overlay everything in the document, maybe give it background black so that nothing is visible. Second I would like to have a small squire window in the overlay which doesn't share the black background, in fact it is somewhat transparent and therefore it would be possible to 'peek' trough that window to see document content. But only the content where this window is. It would be kinda like those "zoom" plugins in which only a small portion is being zoomed, but in this case it would show specific content. Any idea how to create such a thing?
An example of what you can do is the following (it may not be the best but it works)
HTML
<div id='peakview'></div> <!-- This div is your view window -->
<div id='out'>
<div class='overlay'></div>
<div class='overlay'></div>
<div class='overlay'></div>
<div class='overlay'></div>
</div>
The <div> inside of #out will re-size accordingly to the position of #peakview creating the illusion of a full overlay. This can be done with simple css and some calculus.
Mainly what you need is the position of the element on screen.
var h = $(this).offset().top;
var l = $(this).offset().left;
var r = ($(window).width() - ($(this).offset().left + $(this).outerWidth()));
//right offset
var b = ($(window).height() - ($(this).offset().top + $(this).outerWidth()));
//bottom offset
In my example I used .draggable() from jQuery UI to move the div around. And while dragging the 4 divs shown above are adjusting their height and width to fill up the space between #peakview and document border.
An example for the first div
$('.overlay:eq(0)').css({
top: 0,
left: 0,
width: '100%',
height: h //the height is always changing depending on the #peakview .offset().top
});
In this fiddle you will see how the filling divs behave
Another ruff start:
http://jsfiddle.net/XDrSA/
This require some extra work, but it may suit your needs.
HTML:
<div id="yourContent" style="width: 300px; margin:100px auto;">
<input type="button" id="zoom" value="Click to zoom"/>
</div>
<div id="zoomer">
<div id="window">This is your "window"</div>
<div id="overlay_top"></div>
<div id="overlay_left"></div>
<div id="overlay_right"></div>
<div id="overlay_bottom"></div>
</div>
CSS:
body {
margin:0;
padding:0;
}
#zoomer {
height: 100%;
width: 100%;
position: absolute;
top: 0;
display: none;
}
#overlay_top {
height: 20%;
width: 100%;
background-color: black;
position: absolute;
top: 0
}
#overlay_right {
height: 100%;
width: 20%;
background-color: black;
position: absolute;
right: 0;
}
#overlay_left {
height: 100%;
width: 20%;
background-color: black;
position: absolute;
left: 0;
}
#overlay_bottom {
height: 20%;
width: 100%;
background-color: black;
position: absolute;
bottom: 0;
}
#window {
margin: 0 auto;
height: 100%;
width: 80%;
position: absolute;
background-color: rgba(0,0,0,.5);
}
And a piece of javascript:
$('#zoom').click(function() {
$('#zoomer').fadeIn();
});
You may need to stumble with the positioning, and the window will be a fixed size one. Not draggable though.

Categories