Apply CSS style to part of a canvas - javascript

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>

Related

How to vertically and horizontally center a div using javascript and css margin?

I am currently trying to center a rectangle in an image with only using javascript (no css center properties). However, even if the numbers are right, the showing is wrong.
To do this, I use the following code :
$(document).ready(function() {
$(".img-zoom-container").css("width", $("#myimage").width());
$(".img-zoom-container").css("height", $("#myimage").height());
$("#lens_container").css("width", ($("#myimage").width() - $("#lens").width()));
$("#lens_container").css("height", ($("#myimage").height() - $("#lens").height()));
$("#lens_container").css("top", ($("#lens").height() / 2));
$("#lens_container").css("left", ($("#lens").width() / 2));
});
.img-zoom-container
{
border: 1px solid red;
}
#lens
{
border: 1px solid white;
width: 50px;
height: 50px;
position: absolute;
}
#lens_container
{
border: 1px solid cyan;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="img-zoom-container">
<div id="lens"></div>
<div id="lens_container"></div>
<img id="myimage" src="https://via.placeholder.com/600x160.png?text=Testing Image" alt="">
</div>
The item I am trying to center is the #lens_container div (appears blue on screen). I also have a white square (#lens div) of size 50px by 50px. I would like to center and to size the blue rectangle in order to have half of the square width at each side of the blue rectangle and same with height. However, as you can see when trying the code, it is not the case although the maths are correct.
I do not know if you can understand my needs, but I would really appreciate help there.
Thanks in advance.
There are 2 issues:
First, position: absolute means to position the item "to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block" (reference). The parent element ".img-zoom-container" is not positioned. The initial container block would be <body>, which has some padding by default.
So your #lens_container is positioned relative to <body> of the iframe, which is probably not what you expected. Moreover, <body> by default has a non-zero padding size. You may see it clearer if you simply use CSS to position everything to top: 0 and left: 0:
body {
background-color: rgba(0, 0, 0, 0.1);
}
.img-zoom-container
{
border: 1px solid red;
width: 600px;
height: 160px;
}
#lens
{
border: 1px solid white;
width: 50px;
height: 50px;
position: absolute;
top: 0;
left: 0;
}
#lens_container
{
border: 1px solid cyan;
width: 550px;
height: 110px;
position: absolute;
top: 0;
left: 0;
}
<div class="img-zoom-container">
<div id="lens"></div>
<div id="lens_container"></div>
<img id="myimage" src="https://via.placeholder.com/600x160.png?text=Testing Image" alt="">
</div>
To have both #lens and #lens_container positioned relative to .img-zoom-container, you have to give .img-zoom-container a "position" value so it can be the "position ancestor":
$(document).ready(function() {
$(".img-zoom-container").css("width", $("#myimage").width());
$(".img-zoom-container").css("height", $("#myimage").height());
$("#lens_container").css("width", ($("#myimage").width() - $("#lens").width()));
$("#lens_container").css("height", ($("#myimage").height() - $("#lens").height()));
$("#lens_container").css("top", ($("#lens").height() / 2));
$("#lens_container").css("left", ($("#lens").width() / 2));
});
.img-zoom-container
{
border: 1px solid red;
position: relative; /** this line **/
}
#lens
{
border: 1px solid white;
width: 50px;
height: 50px;
position: absolute;
}
#lens_container
{
border: 1px solid cyan;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="img-zoom-container">
<div id="lens"></div>
<div id="lens_container"></div>
<img id="myimage" src="https://via.placeholder.com/600x160.png?text=Testing Image" alt="">
</div>
It's still 1-2 pixels off. That is because you didn't take the border width into consideration (your second issue). You'd get a better result once you clear your head and think how you want the border widths to behave.
Depending on its container, you could just set an ID on your div like:
CONTENT .
Then in javascript, if there is an event to center it, you could make a function like:
function centerDivItem() {
document.getElementById("id1").style.alignContent = "center"
}
And then, as I said, call it from another place.

MouseEvent.clientX and MouseEvent.clientY Unexpected Results With CSS Scale Transform

$('body').on('mousemove', function (ev) {
$('span').text(`x: ${ev.clientX}, y: ${ev.clientY}`)
})
body {
padding: 0;
margin: 0;
}
div {
display: inline-block;
width: 100px;
height: 100px;
background: #333;
transform: scale(2, 2);
}
span {
position: absolute;
left: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="my-div"></div>
<span id="my-span"></span>
I was just wondering why the scaled div returns x and y MouseEvent coordinates in the range from 0 to 150 instead of from 0 to 200? The scale property is set to 2, so I thought it would be the second range instead of the first. Could someone explain? Here's a link to the js fiddle page.
I noticed a lot of similar questions on Stackoverflow, so this might be a duplicate. However, I couldn't find anything that specifically asked this question about pixels, coordinates, and the scale transformation in CSS. I may have missed something, though...
Thanks!
because transform-origin is center by default so half the div is outside the screen from the top/left.
Either update the transform-origin:
$('body').on('mousemove', function (ev) {
$('span').text(`x: ${ev.clientX}, y: ${ev.clientY}`)
})
body {
padding: 0;
margin: 0;
}
div {
display: inline-block;
width: 100px;
height: 100px;
background: #333;
transform: scale(2, 2);
transform-origin:0 0;
}
span {
position: absolute;
left: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="my-div"></div>
<span id="my-span"></span>
Or add some margin:
$('body').on('mousemove', function (ev) {
$('span').text(`x: ${ev.clientX}, y: ${ev.clientY}`)
})
body {
padding: 0;
margin: 0;
}
div {
display: inline-block;
width: 100px;
height: 100px;
background: #333;
transform: scale(2, 2);
margin:50px;
}
span {
position: absolute;
left: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="my-div"></div>
<span id="my-span"></span>
The div is scaled relative to its center, so part of it ends up being off screen. (One way to notice this: add a border to the div and see that it doesn't go all the way around.)
Try using transform-origin: top left; on the div - I think that will do what you expect.

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.

Changing between 2 background colours on mouse Y + adapting <p> to that new colour

I found a piece of code that almost does what I want except I want it to be horizontal / based on mouse Y instead of X. Now I understand that in the js X will be changed to Y, but I struggle with rotating the divs.
Also, if I want to put some text over it, how would I do so that the background change affects the text colour (so if the text is black and half of the background is black, to make sure once when the black background overlays the text, text colour changes to another or gets inverted for example?
Also also, I tried to figure out in js which part dictates the responsiveness of the mouse movement, i.e., how would you do so that the colour shifting is not lagging after the mouse but I couldn't figure out?
https://codepen.io/erutuf/pen/NJLwqV
haml
#banner-wrapper.banner-wrapper
.banner.design
.banner-content
.banner.dev
.banner-content
scss
body {
margin: 0;
padding: 0;
.banner-wrapper {
position: relative;
width: 100%;
height: 400px;
overflow: hidden; background:red;
}
.banner {
position: absolute;
overflow: hidden;
&.dev {
margin-left: -500px;
width: calc(50vw + 500px);
.banner-content {
margin-left: 500px; background:black;
}
}
.banner-content {
height: 400px;
}
img {
width: 100vw;
}
}
}
js
document.addEventListener('DOMContentLoaded', function(){
let banner = document.getElementById('banner-wrapper');
let devLayer = banner.querySelector('.dev');
let delta = 0;
banner.addEventListener('mousemove', function(e){
delta = (e.clientX - window.innerWidth / 2) * 0.5;
devLayer.style.width = e.clientX + 500 + delta + 'px';
});
})
you can play with JS + CSS. The following code can be your starting point :).
btw i'm adapting code from your link https://codepen.io/erutuf/pen/NJLwqV
document.addEventListener("DOMContentLoaded", function(){
let banner = document.getElementById("banner-wrapper");
let devLayer = banner.querySelector(".dev");
let delta = 0;
// play with div's height
banner.addEventListener("mousemove", function(e){
delta = (e.clientY - window.innerHeight / 2) * 0.5;
devLayer.style.height = e.clientY + delta + "px";
});
})
<div class="banner-wrapper" id="banner-wrapper">
<div class="banner design">
<div class="banner-content">BANNER TEXT</div>
</div>
<div class="banner dev">
<div class="banner-content"></div>
</div>
</div>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
body .banner-wrapper {
position: relative;
width: 100%;
height: 200px;
overflow: hidden;
background: red;
}
body .banner {
position: absolute;
overflow: hidden;
}
body .banner.dev {
width: 100%;
/* play with responsiveness here. note that 0.1 is more responsive than 0.5. more info : https://www.w3schools.com/css/css3_transitions.asp */
-webkit-transition: height 0.2s linear;
transition: height 0.2s ease;
}
body .banner.dev .banner-content {
background: black;
}
body .banner .banner-content {
height: 400px;
}
body .banner img {
width: 100%;
}
.banner.design {
margin-top: -25px;
height: 50px;
top: 50%;
font-size: 50px;
/* set color & mix-blend-mode for text color vs background color effect. more info : https://css-tricks.com/methods-contrasting-text-backgrounds/ */
mix-blend-mode: difference;
color: #fff;
z-index: 1;
margin-left: -175px;
left: 50%;
width: 350px;
}
</style>

Inscribe and center an image within a frame

Given a div of arbitrary aspect ratio, what's the best way to place and style an image (also with an arbitrary aspect ratio) inside such that:
It is both inscribed and centered
Its dimensions and position are set using relative values so that the image will remain inscribed and centered automatically when the frame is uniformly scaled (javascript should only be required when the image is initially inserted, or if the frame's aspect ratio changes)
Extra markup is minimized
Here's the result we want:
Here's a fiddle template, which is just:
Markup
Should pillarbox
<div class="frame">
<img src="http://www.placekitten.com/200/300" />
</div>
Should letterbox
<div class="frame">
<img src="http://www.placekitten.com/300/200" />
</div>
CSS
.frame {
width: 200px;
height: 200px;
border: 2px solid black;
margin: 10px 0px 100px 0;
}
You can try something like this: updated fiddle
.frame {
width: 200px;
height: 200px;
border: 2px solid black;
margin: 10px 0px 100px 0;
position: relative; /* added */
}
img {
max-height: 100%;
max-width: 100%;
position: absolute;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
By combining Adrift's css
.frame {
width: 400px;
height: 400px;
border: 2px solid black;
margin: 10px 0px 100px 0;
position: relative; /* added */
}
img {
max-height: 100%;
max-width: 100%;
position: absolute;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
with javascript
var inscribe = function(img, frame) {
var imgRatio = img.width / img.height;
var frameRatio = frame.offsetWidth / frame.offsetHeight;
if (imgRatio > frameRatio) { // image is wider than frame; letterbox
img.style.width = '100%';
img.style.height = 'auto';
} else { // image is taller than frame; pillarbox
img.style.width = 'auto';
img.style.height = '100%';
}
}
all requirements can be satisfied.
http://jsfiddle.net/PBPkh/4/
Well you can achieve that with background-images too, if you can get rid of the <img /> elements.
There is a css property on background-size called contain, that does the job:
.background{
background-size: contain;
}
And if you wish to center the image just add this:
background-position: center center;

Categories