I have an HTML file with this:
<div id="container"></div>
and I have a stylesheet with a CSS3 animation defined:
.image {
position: absolute;
-webkit-animation-name: image-create;
-webkit-animation-duration: 1s;
}
#-webkit-keyframes image-create {
from {
width: 0px;
height: 0px;
}
to {
width: 500px;
height: 500px;
}
}
This should make an image grow from 0x0 to 500x500.
In my Javascript file I have the following:
var findAnimation = function(name) {
for (var i in document.styleSheets) {
var styleSheet = document.styleSheets[i];
for (var j in styleSheet.cssRules) {
var rule = styleSheet.cssRules[j];
if (rule.type === 7 && rule.name == name) {
return rule;
}
}
}
return null;
}
var addImage = function(x, y, src) {
var image = new Image();
image.src = src;
image.className = "image";
image.style.width = "500px";
image.style.height = "500px";
image.style.left = x;
image.style.top = y;
image.onload = function() {
document.getElementById("container").appendChild(image);
var animation = findAnimation("image-create");
for (var i in animation.cssRules) {
var rule = animation.cssRules[i];
if (rule.keyText == "0%") {
rule.style.top = y;
rule.style.left = x;
}
if (rule.keyText == "100%") {
rule.style.top = 0;
rule.style.left = 0;
}
}
}
}
addImage(100, 100, "http://i.imgur.com/KGfgH.jpg");
When addImage() is called, I'm trying to create an image at the coordinates (x, y). The animation should make it grow while also move from the location where the image was created (x, y) to the top left corner (0, 0).
Instead, Chrome just crashes to the "Aw, snap" page. Does anyone know why this is the case?
EDIT: Here is an example. This crashes for me if I visit it: http://jsfiddle.net/LVpWS/10/
In this one I commented out some lines and it does not crash: http://jsfiddle.net/LVpWS/21/
EDIT2: It works if I switch back to Chrome 20.
I've isolated the error:
The page crashes (Aw, snap) when a new property is added to a WebKitCSSKeyframeRule instance.
The bug can be reproduced in Chrome 21.0.1180.57 using the following code: http://jsfiddle.net/LVpWS/68/
<style id="sheet">
#-webkit-keyframes test {
from {}
}</style><script>
var keyFramesRule = document.getElementById('sheet').sheet.cssRules[0];
var keyFrameRule = keyFramesRule[0];
keyFrameRule.style.top = 0;</script>
This crash does not happen when the property already exists in the rule. Replace from {} with from{top:1px;} to check that: http://jsfiddle.net/LVpWS/69/.
Related
I am a Beginner Developer and am working on a personal chess project.
I just learned how to create a drag and drop system, maybe I could learn other ways of doing It but I would like to know if there's any way to 'remove' the white background.
I don't know really how this should work but I had some ideas:
Somehow remove the white background of the ghost image.
Substitute the ghost image with the actual image being dragged.
Or just entirely remove the ghost image while dragging since we can see the piece in each square when you are dragging over it.
If it's possible to do any of these solutions it would be good!
Here is the link for the project I am working: https://codepen.io/ThalisonAmaral/full/qBYZmZq
You will be probably dealing with the function dragstart();
`
function dragstart() {
squaresDrop.forEach(square => square.classList.add('highlight'))
this.classList.add('is-dragging');
}
`
The Drag and Drop is at the end of the Js Code
Since I don't understand what I am dealing with exactly.
I searched for some possible solutions but I couldn't get any result with
DataTransfer.setDragImage().
Which I think it should be using for replacing the ghost image with an actual image but I would need to check each piece, It doesn't seem to be the way but I could be wrong.
The easiest way of doing this is by setting the opactiy of the image to 0 when you start dragging it and setting it back to 1 when dropping.
I added this.style.opacity = 0; on line 105
and this.style.opacity = 1; on line 11
Hopefully this is what you want!
/* ------- BOARD GENERATOR -------*/
const body = document.body;
const $addClass = (element,className) => {
element.classList.add(className);
};
const $setId = (element,idName)=>{element.setAttribute('id',idName)}
const $createSquare = (element,squareColor,board)=> {
element = document.createElement('div');
$addClass(element,squareColor)
$addClass(element,'square');
board.appendChild(element)
};
const $createBoardBorder = (where) => {
var board = document.createElement('div');
$addClass(board,'board');
where.appendChild(board)
}
var coordinates = [
'a8','b8','c8','d8','e8','f8','g8','h8',
'a7','b7','c7','d7','e7','f7','g7','h7',
'a6','b6','c6','d6','e6','f6','g6','h6',
'a5','b5','c5','d5','e5','f5','g5','h5',
'a4','b4','c4','d4','e4','f4','g4','h4',
'a3','b3','c3','d3','e3','f3','g3','h3',
'a2','b2','c2','d2','e2','f2','g2','h2',
'a1','b1','c1','d1','e1','f1','g1','h1'
];
function createBoard(size,lightColor,darkColor,where){
/* CREATING A DIV WITH A CLASS 'board' */
$createBoardBorder(where);
/* SELECTING THE BOARD */
var board = document.querySelector('.board');
/* GENERATING ALL THE SQUARES AND PUTTING THEM INTO THE BOARD */
var light = 'light'; var dark = 'dark';
for (let i = 0; i < 32; i++) {
$createSquare(coordinates,light,board);
$createSquare(coordinates,dark,board);
if((i+1)%4 === 0 ){
var x = light;
light = dark;
dark = x;
}
}
const squares = document.querySelectorAll('.square');
/*PUTTING ALL THE IDS IN EACH SQUARE */
for (let i = 0; i < squares.length; i++) {
$setId(squares[i],coordinates[i])
}
// ----- BOARD STYLE -----
const lightSquares = document.querySelectorAll('.light');
const darkSquares = document.querySelectorAll('.dark');
board.style.width = size+'px';
board.style.height = size+'px';
lightSquares.forEach((value,index)=>{
value.style.height = size/8+'px';
value.style.width = size/8+'px';
value.style.backgroundColor = lightColor;
darkSquares[index].style.height = size/8+'px';
darkSquares[index].style.width = size/8+'px';
darkSquares[index].style.backgroundColor = darkColor;
})
}
const boardzone = document.getElementById('boardzone');
createBoard(500,'white','rgb(64, 100, 145)',boardzone);
/*-------- PIECE RENDER --------*/
const king = document.createElement('img');
king.setAttribute('class','piece');
king.src = "https://images.chesscomfiles.com/chess-themes/pieces/neo/150/wk.png";
e1.appendChild(king)
/*-------- DRAG AND DROP --------*/
var audio = new Audio('sound.wav');
var pieces = document.querySelectorAll('.piece');
console.log(pieces);
var squaresDrop = document.querySelectorAll('.square');
pieceCheck = ()=> {
var pieces = document.querySelectorAll('.piece');
pieces.forEach(piece=>{
piece.addEventListener('dragstart',dragstart)
piece.addEventListener('drag',drag)
piece.addEventListener('dragend',dragend)
function dragstart() {
squaresDrop.forEach(square => square.classList.add('highlight'))
this.style.opacity = 0;
this.classList.add('is-dragging');
}
function drag(){
}
function dragend(){
this.style.opacity = 1;
this.classList.remove('is-dragging');
audio.play();
}
})}
pieceCheck(); //Checking if a new piece was added in the board
squaresDrop.forEach(square=>{
square.addEventListener('dragenter',dragenter);
square.addEventListener('dragover',dragover);
square.addEventListener('dragleave',dragleave);
square.addEventListener('drop',drop);
function dragenter(){
}
function dragover(){
this.classList.add('over')
//Get dragging piece
const draggedPiece = document.querySelector('.is-dragging');
this.appendChild(draggedPiece);
}
function dragleave(){
log('Leaving')
this.classList.remove('over')
}
function drop(){
}
})
body {
background-color:rgb(15,15,15);
}
.board {
display: grid;
grid-template-columns: repeat(8, 1fr);
}
#boardzone{
margin: 60px auto;
display: flex;
justify-content:center;
}
/* Drag and Drop CSS */
.piece {
height: 100%;
user-select: none;
}
.highlight {
background-color:rgba(14,14,14,0.2);
}
.is-dragging {
cursor:move;
opacity: 0.3;
transform: translate(0, 0);
}
.over{
background-color: rgba(173, 240, 118, 0.315);
}
<div id='boardzone'></div>
This code populates a div with a predefined set of gradients and fades through them in a cycle using jQuery's .animate() method:
/// Background Gradient Cycler
var gradients = [
['#9eb5d7', '#242424'],
['#efe2ae', '#a8acc9'],
['#6f7554', '#eee1ad']
]
var gradientsRev = gradients.reverse()
var gradientCover = document.getElementById('gradientCover');
for (var g = 0; g < gradientsRev.length; g++) {
var gradEl = document.createElement('div')
gradEl.className = 'gradient'
gradEl.style.background = `linear-gradient(${gradientsRev[g][0]}, ${gradientsRev[g][1]})`;
gradientCover.appendChild(gradEl)
}
var gradientEls = document.querySelectorAll('#gradientCover .gradient')
function gradientCycler() {
function gradeFade(i, opDest) {
var fadeDur = 20000
$(gradientEls[i]).animate({
'opacity': opDest
}, {
duration: fadeDur,
complete: function() {
if (parseInt(i) > 1) {
if (parseInt(opDest) === 0) gradeFade(i - 1, 0)
else gradFadeStart()
} else {
gradeFade(gradientEls.length - 1, 1)
}
}
})
}
var gradFadeStart = function() {
$('.gradient').css('opacity', 1);
gradeFade(gradientEls.length - 1, 0)
}
gradFadeStart()
}
gradientCycler()
body {
margin: 0;
overflow: hidden;
}
#gradientCover,
.gradient {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<div id="page">
<div id="gradientCover"></div>
</div>
The problem is that the transition at certain parts is visibly choppy, with banding artifacts --
What can be done to reduce this artifacting so that the transition between the gradients appears smoother and less choppy?
I think is related to color depth, As a former CG artist I have seen these "artefacts" in software like Maya and Photoshop, to solve the problem it was necessary to increase the number of bits per channel (in Photoshop going from 8 Bits/Channel to 16).
Normally, this issue of bands appears when the two colors of the gradient are close (in term of RGB values) because there are few values of colors available between these two colors
If the gradient is rendered OR displayed (due to the monitor limitation) at a low number of bits per channel these banding effect can appear.
You can check your monitor color depth here.
You can also apply CSS according to this value:
if (screen.colorDepth <= 8)
//simple blue background color for 8 bit screens
document.body.style.background = "#0000FF"
else
//fancy blue background color for modern screens
document.body.style.background = "#87CEFA"
Including my codepen tests here as an answer just in case it helps anyone. I managed to get some improved performance by pre-rendering PNGs with the canvas' .toDataURL() method and animating through them in jQuery (also achieved about the same performance with this method but using Three.js):
https://codepen.io/tv/zxBbgK
Here's a working example of the JQuery method:
/// Background Gradient Cycler
var gradients = [
['#9eb5d7', '#242424'],
['#efe2ae', '#a8acc9'],
['#6f7554', '#eee1ad']
]
var gradientsRev = gradients.reverse()
var gradientCover = document.getElementById('gradientCover');
for (var g = 0; g < gradientsRev.length; g++) {
var gradEl = document.createElement('div')
gradEl.className = 'gradient'
var gradCanv = document.createElement('canvas')
gradCanv.className = 'gradient'
var ctx = gradCanv.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 0, gradCanv.height);
grd.addColorStop(0, gradients[g][0]);
grd.addColorStop(1, gradients[g][1]);
ctx.fillStyle = grd;
ctx.fillRect(0, 0, gradCanv.width, gradCanv.height);
var gradIm = gradCanv.toDataURL("img/png")
gradEl.style.backgroundImage = `url(${gradIm})`
gradientCover.appendChild(gradEl)
}
var gradientEls = document.querySelectorAll('#gradientCover .gradient')
function gradientCycler() {
function gradeFade(i, opDest) {
var fadeDur = 20000
$(gradientEls[i]).animate({
'opacity': opDest
}, {
duration: fadeDur,
complete: function() {
if (parseInt(i) > 1) {
if (parseInt(opDest) === 0) gradeFade(i - 1, 0)
else gradFadeStart()
} else {
gradeFade(gradientEls.length - 1, 1)
}
}
})
}
var gradFadeStart = function() {
$('.gradient').css('opacity', 1);
gradeFade(gradientEls.length - 1, 0)
}
gradFadeStart()
}
gradientCycler()
body {
margin: 0;
overflow: hidden;
}
#gradientCover,
.gradient {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-size: 100%;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<div id="page">
<div id="gradientCover"></div>
</div>
OK so I've tried one thing from a different question and it worked, but not the way I wanted it to. it didn't work the way I wanted it to! You literally had to click when two objects were touching so it would alert you, if somebody can figure out a way to detect if two elements are touching without having to click that would be a life saver! So I hope you people who read this request please respond if you know how. this is the code below. so one object is moving and i want it to make it stop when the object hits the player (i am making a game) the movement is by px.... i want it to keep testing if one object hits the player, and if it does i want it to stop everything.
var boxes = document.querySelectorAll('.box');
boxes.forEach(function (el) {
if (el.addEventListener) {
el.addEventListener('click', clickHandler);
} else {
el.attachEvent('onclick', clickHandler);
}
})
var detectOverlap = (function () {
function getPositions(elem) {
var pos = elem.getBoundingClientRect();
return [[pos.left, pos.right], [pos.top, pos.bottom]];
}
function comparePositions(p1, p2) {
var r1, r2;
if (p1[0] < p2[0]) {
r1 = p1;
r2 = p2;
} else {
r1 = p2;
r2 = p1;
}
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
function clickHandler(e) {
var elem = e.target,
elems = document.querySelectorAll('.box'),
elemList = Array.prototype.slice.call(elems),
within = elemList.indexOf(elem),
touching = [];
if (within !== -1) {
elemList.splice(within, 1);
}
for (var i = 0; i < elemList.length; i++) {
if (detectOverlap(elem, elemList[i])) {
touching.push(elemList[i].id);
}
}
if (touching.length) {
console.log(elem.id + ' touches ' + touching.join(' and ') + '.');
alert(elem.id + ' touches ' + touching.join(' and ') + '.');
} else {
console.log(elem.id + ' touches nothing.');
alert(elem.id + ' touches nothing.');
}
}
this is my video game right now (please do not copy)
<!DOCTYPE html>
/
<html>
<form id="player" class="box">
</form>
<button type="button" class="up" onclick="moveup()">^</button>
<button type="button" class="down" onclick="movedown()">v
</button>
<style src="style.css">
#player {
width: 300px;
height: 100px;
background-color: blue;
display: inline-block;
position: relative;
bottom: -250px;
left: 200px;
}
.up {
position: relative;
bottom: -400px;
}
.down {
position: relative;
bottom: -420px;
}
body {
background-color: black;
}
#car {
width: 300px;
height: 100px;
background-color: red;
display: inline-block;
position: relative;
bottom: -250px;
left: 600px;
}
</style>
<form id="car" class="box"></form>
<script>
imgObj = document.getElementById('player');
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
function moveup() {
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
imgObj.style.bottom = parseInt(imgObj.style.bottom) + 70 + 'px';
}
function movedown() {
imgObj.style.position= 'relative';
imgObj.style.bottom = '-250px';
imgObj.style.bottom = parseInt(imgObj.style.bottom) + -120 + 'px';
}
myMove();
function myMove() {
var elem = document.getElementById("car");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 1000) {
clearInterval(id);
myMove();
} else {
pos++;
elem.style.left = pos + "px";
elem.style.left = pos + "px";
}
}
}
/* please do not copy; this is it so far i want the red box when it hits the player(blue box) to stop everything that is happening */
/* made by Jsscripter; car game */
</script>
</html>
Intersection observer. API was largely developed because of news feeds and infinite scrolling. Goal was to solve when something comes into view, load content. Also is a great fit for a game.
The Intersection Observer API lets code register a callback function
that is executed whenever an element they wish to monitor enters or
exits another element (or the viewport), or when the amount by which
the two intersect changes by a requested amount. This way, sites no
longer need to do anything on the main thread to watch for this kind
of element intersection, and the browser is free to optimize the
management of intersections as it sees fit.
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
All major browsers except safari support the API. For backwards compatibility and Safari support can use the polyfill from W3C found here. Check out this example from MDN:
var callback = function(entries, observer) {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// target element:
// entry.boundingClientRect
// entry.intersectionRatio
// entry.intersectionRect
// entry.isIntersecting
// entry.rootBounds
// entry.target
// entry.time
});
};
var options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
var observer = new IntersectionObserver(callback, options);
var target = document.querySelector('#listItem');
observer.observe(target);
See this in action here: https://codepen.io/anon/pen/OqpeMV
I am working on a project where I have a slideshow with images as follows:
img {
width:100vw;
height:100vh;
object-fit:cover;
}
This makes the images fullscreen and behave like background-size:cover, so they fill out the whole viewport on any screen size without distortion.
I would like to tag certain points with text tooltips on these images. For this purpose I have found Tim Severien's Taggd, which works great on responsive images, but in my case the object-fit:cover; property makes the tagged positions inaccurate.
I have tried everything from CSS hacks to improving Tim's code, but I am out of ideas. If you have any solution or workaround in mind please share.
Thank you!
well i actually wanted to do the same thing.
here is what i've done.
maybe it will help someone in the future.
it would be great if this feature could be integrated in taggd.
function buildTags()
{
// be aware that image.clientWidth and image.clientHeight are available when image is loaded
var croppedWidth = false;
var expectedWidth = 0;
var croppedWidthHalf = 0;
var imageWidth = 0;
var croppedHeight = false;
var expectedHeight = 0;
var croppedHeightHalf = 0;
var imageHeight = 0;
var naturalRatio = image.naturalWidth/image.naturalHeight;
var coverRatio = image.clientWidth/image.clientHeight;
if(Math.abs(naturalRatio - coverRatio) < 0.01)
{
// the image is not cropped, nothing to do
}
else
{
if(naturalRatio > coverRatio)
{
// width is cropped
croppedWidth = true;
expectedWidth = image.clientHeight * naturalRatio;
croppedWidthHalf = (expectedWidth - image.clientWidth)/2;
imageWidth = image.clientWidth;
}
else
{
// height is cropped
croppedHeight = true;
expectedHeight = image.clientWidth / naturalRatio;
croppedHeightHalf = (expectedHeight - image.clientHeight)/2;
imageHeight = image.clientHeight;
}
}
function calcy(y)
{
if(croppedHeight)
{
var positiony = y * expectedHeight;
if(positiony > croppedHeightHalf)
return (positiony - croppedHeightHalf)/imageHeight;
else // tag is outside the picture because cropped
return 0; // TODO : handle that case nicely
}
else
return y;
}
function calcx(x)
{
if(croppedWidth)
{
var positionx = x * expectedWidth;
if(positionx > croppedWidthHalf)
return (positionx - croppedWidthHalf)/imageWidth;
else // tag is outside the picture because cropped
return 0; // TODO : handle that case nicely
}
else
return x;
}
var tags = [
Taggd.Tag.createFromObject({
position: { x: calcx(0.74), y: calcy(0.56) },
text: 'some tag',
}),
Taggd.Tag.createFromObject({
position: { x: calcx(0.9), y: calcy(0.29) },
text: 'some other tag',
}),
....
];
var taggd = new Taggd(image, options, tags);
}
$(window).bind("load", function() {buildTags();});
Is not possible. Think if the user has a tablet with 1024x768 resolution, when the user change view from horizontal to vertical the image can fill the space but you will loose part of the image, loose img quality, etc.
The best way for cross devices is to use big pictures and add in css
img {
height: auto;
width: 100%;
display: block;
}
And fill image background with a color;
I have a page wherein the background image for a particular div keeps changing dynamically. I wanna be able to give some transition effects on the images. The page runs on pure javascript. Here's my code:
var bgArray = ["images/1.jpg", "images/2.jpg", "images/3.jpg"];
var i = 0;
function myFunction() {
setInterval(function() {
if (i == 3) {
i = 0;
}
var urlString = bgArray[i];
var x = document.getElementById("myDiv");
x.style.background = "url(" + bgArray[i] + ") no-repeat";
x.style.backgroundSize = "1366px";
i = i + 1;
}, 6000);
}
myFunction();
Thank you.
#myDiv {
transition: background 1s;
}
HTML code
<div id = "myDiv"></div>
CSS code
#myDiv{
width: <yourDivWidth>;
height: <yourDivHeight>;
background-size: cover;
}
Javascript code
var box = document.getElementById("myDiv");
var imagesList = ["url('images/1.jpg')", "url('images/2.jpg')", "url('images/3.jpg')"];
i = 0;
box.style.backgroundImage = imagesList[i];
function nextImg(){
box.style.backgroundImage = imagesList[i+1];
//box.style.width = "1366px";
//box.style.height = "1366px";
//declare your width and height of div in css and give background-size: cover;.
i = i+1;
if(i == imagesList.length){
i = 0;
box.style.backgroundImage = imagesList[i];
}
}
window.onload = setInterval(nextImg, 6000);
Wait for 6 sec and see the background images changing.
If you want to set background image for the first 6sec also, then you can set that in your CSS.
Comment if u have any doubts.