SpriteSheets, CSS, HTML5 and Safari - Why the performance hiccup? - javascript

http://kazopark.com/3d/car/
This animation is using a spritesheet.
This animations works completely fine in Firefox and Chrome, as well as the latest versions of IE.
However, when it comes to Safari, it's just not working as you'd expect. The animation speed is incredibly slow, dropping to as little as 15 FPS.
Is there anyway of making something like this work the same across all the browsers, without purposely slowing the others down?
I suspect this is to do with the inadequate way that Safari handles large images?
It should be noted, I have reduced the filesize all the way down to 1.8mb for this, down from 4.3mb. It's still not playing properly.
Code for animation:
/********************************
* INIT ON LOAD *
* PUBLIC *
*********************************/
KMS.background = function(){
var singleton = {};
this.parent;
this.imgHolder;
this.newWidth;
this.newHeight;
function init(){
parent = document.createElement('div');
parent.className = "KMS_div";
parent.id = "KMS_div_Background";
var holder = document.getElementById("KMS_div_Holder");
holder.appendChild(parent);
imgHolder = new Image();
imgHolder.id = "KMS_img_SpriteSheet";
imgHolder.src = "img/CarRoad_low2.jpg";
parent.appendChild(imgHolder);
newWidth = window.innerWidth / 800;
newHeight = window.innerHeight / 600;
imgHolder.style.width = 512 + "%";
imgHolder.style.height = 1365.4 + "%";
}
function BeginBackground(){
init();
var i = 0;
setInterval(function(){
parent.style.left = -(100 * (i % 5)) + "%";
parent.style.top = -(100 * (parseInt(i / 5) % 14)) + "%";
i++;
if(i === 63) i = 0;
console.log(i);
}, 50);
console.log("BG begin");
};
singleton.BeginBackground = BeginBackground;
return singleton;
}();

Related

Resize window with smooth transition for different height sizes

Some context:
I'm working on a Chrome Extension where the user can launch it via default "popup.html", or if the user so desires this Extension can be detached from the top right corner and be used on a popup window via window.open
This question will also apply for situations where users create a Shortcut for the extension on Chrome via:
"..." > "More tools" > "Create Shortcut"
Problem:
So what I need is for those cases where users use the extension detached via window.open or through a shortcut, when navigating through different options, for the Height of the window to be resized smoothly.
I somewhat achieve this but the animation is clunky and also the final height is not always the same. Sometimes I need to click twice on the button to resize too because 1 click won't be enough. Another issue is there is also some twitching of the bottom text near the edge of the window when navigating.
Here's what I got so far:
(strWdif and strHdif are used to compensate for some issues with CSS setting proper sizes which I haven't figured out yet.)
const popup = window;
function resizeWindow(popup) {
setTimeout(function () {
var strW = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("width");
var strW2 = strW.slice(0, -2);
var strWdif = 32;
var bodyTargetWidth = (parseFloat(strW2) + parseFloat(strWdif));
var strH = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("height");
var strH2 = strH.slice(0, -2);
var strHdif = 54;
var bodyTargetHeight = (parseFloat(parseInt(strH2)) + parseFloat(strHdif));
var height = window.innerHeight;
console.log("Window Height: ", height, "CSS Height: ", bodyTargetHeight);
var timer = setInterval(function () {
if (height < bodyTargetHeight) {
popup.resizeTo(bodyTargetWidth, height += 5);
if (height >= bodyTargetHeight) {
clearInterval(timer);
}
} else if (height > bodyTargetHeight) {
popup.resizeTo(bodyTargetWidth, height -= 5);
if (height <= bodyTargetHeight) {
clearInterval(timer);
}
} else {
clearInterval(timer);
}
}, 0);
}, 0400);
}
Question:
Is there a way to make this more responsive, and smooth and eliminate all the twitching and clunkiness?
I guess the issue might be that I am increasing/diminishing by 5 pixels at a time but that is the speed I need. Maybe there is another way to increase/decrease by 1px at a faster rate? Could this be the cause of the twitching and clunkiness?
Also, I should add that troubleshooting this is difficult because the browser keeps crashing so there is also a performance issue sometimes when trying different things.
EDIT:
Another option using resizeBy:
function animateClose(time) {
setTimeout(function () {
var strW = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("width");
var strW2 = strW.slice(0, -2);
var strWdif = 32;
var bodyTargetWidth = (parseFloat(strW2) + parseFloat(strWdif));
var strH = getComputedStyle(window.document.querySelector(".body_zero")).getPropertyValue("height");
var strH2 = strH.slice(0, -2);
var strHdif = 54;
var bodyTargetHeight = (parseFloat(parseInt(strH2)) + parseFloat(strHdif));
var w = window.innerWidth; //Get window width
var h = window.innerHeight; //Get window height
var loops = time * 0.1; //Get nb of loops
var widthPercentageMinus = (w / loops) * -0;
var heightPercentageMinus = (h / loops) * -1;
var widthPercentagePlus = (w / loops) * +0;
var heightPercentagePlus = (h / loops) * +1;
console.log("Window Height: ", h, "CSS Height: ", bodyTargetHeight);
var loopInterval = setInterval(function () {
if (h > bodyTargetHeight) {
window.resizeBy(widthPercentageMinus, heightDecrheightPercentageMinuseasePercentageMinus);
} else if (h < bodyTargetHeight) {
window.resizeBy(widthPercentagePlus, heightPercentagePlus);
} else {
clearInterval(loopInterval);
}
}, 1);
}, 0400);
}
This one is a bit more smooth but I can't make it stop at the desired Height. It also is not differentiating between resizing up or down, also crashes the browser sometimes.
maybe with requestAnimationFrame
try something like this (not tested):
function resizeWindow(popup) {
var gcs = getComputedStyle(window.document.querySelector(".body_zero"));
var strW = gcs.getPropertyValue("width");
var strW2 = strW.slice(0, -2);
var strWdif = 32;
var bodyTargetWidth = (parseFloat(strW2) + parseFloat(strWdif));
var strH = gcs.getPropertyValue("height");
var strH2 = strH.slice(0, -2);
var strHdif = 54;
var bodyTargetHeight = (parseFloat(parseInt(strH2)) + parseFloat(strHdif));
var height = window.innerHeight;
console.log("Window Height: ", height, "CSS Height: ", bodyTargetHeight);
window.myRequestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var hStep = 2; //choose the step. Must be an integer
function internalFunc() {
if (Math.abs(height - bodyTargetHeight) > hStep) {
if (height < bodyTargetHeight)
hStep *= 1;
else if (height > bodyTargetHeight)
hStep *= -1;
popup.resizeBy(0, hStep);
height += hStep;
window.myRequestAnimationFrame(internalFunc)
} else
popup.resizeBy(0, bodyTargetHeight - height)
}
popup.resizeTo(bodyTargetWidth, height);
window.myRequestAnimationFrame(internalFunc)
}
<html>
<head>
<script>
const bodyTargetWidth = 150;
const bodyTargetHeight = 250; //target height
var height; //height at beginning
window.myRequestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
var hStep = 5; //choose the step. Must be an integer
var dir;
var myPopup;
function doResize() {
function internalFunc() {
console.log('height: ', height) ;
if (Math.abs(height - bodyTargetHeight) > hStep) {
dir = Math.sign(bodyTargetHeight - height);
myPopup.resizeBy(0, dir * hStep);
height += dir * hStep;
window.myRequestAnimationFrame(internalFunc)
} else
myPopup.resizeBy(0, bodyTargetHeight - height)
}
if (!myPopup || myPopup?.closed) {
myPopup = window.open("about:blank", "hello", "left=200,top=200,menubar=no,status=no,location=no,toolbar=no");
height = 150;
myPopup.resizeTo(bodyTargetWidth, height);
} else {
myPopup.focus();
height = myPopup.outerHeight
}
myPopup.resizeTo(bodyTargetWidth, height);
window.myRequestAnimationFrame(internalFunc)
}
document.addEventListener('DOMContentLoaded', _ => document.getElementById('myBtn').addEventListener('click', doResize))
</script>
</head>
<body>
<button type="button" id="myBtn">Create popup<br>\<br>Reset popup height</button><br>
<p>First create the popup, then change popup height and click the button above again</p>
</body>
</html>

Edge (IE11) Canvas offset with SVG drawing

I want to draw a serialized DOM element in the canvas. It works perfect on
Chrome, Firefox, Safari and Opera but i have problems on Edge (and IE11 (this not crucial)).
This is how I handle the canvas drawing:
this._$svgElement = this._props._svgContainer.find('svg');
this._initSVGWidth = this._$svgElement.width();
this._initSVGHeight = this._$svgElement.height();
var svgURL = new XMLSerializer().serializeToString(this._$svgElement[0]);
var svgString = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgURL);
var newImageWidth, newImageHeight;
this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
this._img = new Image();
this._img.onload = function () {
if (bowser.msie) {
newImageHeight = (this._initSVGHeight / this._initSVGWidth) * this._canvas.width;
newImageWidth = this._canvas.width;
if (newImageHeight >= this._canvas.height) {
newImageHeight = this._canvas.height;
newImageWidth = (this._initSVGWidth / this._initSVGHeight) * this._canvas.height;
}
} else {
newImageHeight = this._img.height / this._img.width * this._canvas.width;
newImageWidth = this._canvas.width;
if (newImageHeight > this._canvas.height) {
newImageHeight = this._canvas.height;
newImageWidth = this._img.width / this._img.height * this._canvas.height;
}
}
//original image values (never changed)
this._imgData = {
x: (this._canvas.width / 2 - newImageWidth / 2),
y: (this._canvas.height / 2 - newImageHeight / 2),
w: newImageWidth,
h: newImageHeight
};
this._ctx.drawImage(this._img, this._imgData.x, this._imgData.y, newImageWidth, newImageHeight);
}.bind(this);
this._img.src = svgString;
The result is a strange offset on the microsoft browsers:
Edge browser (wrong)
For Example: Chrome Browser (how it should be)
This is the SVG Test Source: https://s.cdpn.io/3/kiwi.svg
I don't know what the issue is here. Because even if I try to draw it with drawImage(this._img, 0, 0) the resulting image is cut off.
I'm thankful for any suggestions because we are out of any ideas.

How to make a snow fall on web page text?

I have this JavaScript code for snow falling effect. It's working really nice,
but I decided to create a snow falling on web page text. I have tried, but not getting how to do it.
How to make snow fall on that "I love you" text? http://jsfiddle.net/DgrxX/22/
I have already seen in VB6 code where snow fall on text. If it is possible in Visual Basic 6 seven years ago, why not today in JavaScript or CSS3 or jQuery?
function vp(woh)
{
var viewportwidth;
var viewportheight;
if (typeof window.innerWidth != 'undefined')
{
viewportwidth = window.innerWidth,
viewportheight = window.innerHeight
}
else if (typeof document.documentElement != 'undefined'
&& typeof document.documentElement.clientWidth !=
'undefined' && document.documentElement.clientWidth != 0)
{
viewportwidth = document.documentElement.clientWidth,
viewportheight = document.documentElement.clientHeight
}
else
{
viewportwidth = document.getElementsByTagName('body')[0].clientWidth,
viewportheight = document.getElementsByTagName('body')[0].clientHeight
}
if (woh == 'w')
{
return viewportwidth;
}
else if (woh == 'h')
{
return viewportheight;
}
else
{
return false;
}
}
function snowflake()
{
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.radius = Math.random()*2;
this.color = "white";
var tobefallingSpeed = Math.random() * 100;
this.fallingSpeed = tobefallingSpeed + 30;
}
function render()
{
ctx.clearRect(0,0,canvas.width, canvas.height);
for (b=0;b<snowflakes;b++)
{
sf[b].y+=0.4;
if(sf[b].y> canvas.height){
sf[b].y = 0;
}
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(sf[b].x,sf[b].y,sf[b].radius,sf[b].radius);
}
}
function main()
{
now = Date.now();
delta = now - then;
render();
then = now;
}
then = Date.now();
var int = self.setInterval(main,1);
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = vp('w');
canvas.height = vp('h');
document.body.appendChild(canvas);
var numberofSnowflakes = 100;
var sf = [];
for (i=0;i<numberofSnowflakes;i++)
{
sf[i] = new snowflake();
snowflakes = i;
}
Okay so I have seen a few answers but the asker wants the snow to be exclusively piling up on the text. Exact piling (according to the snow in background) would be really very difficult but I would like to suggest a (maybe complex) working method.
Make images.
A lots of them. With the text 'I love You' and contents of snow different in each. This maybe similar to creating picture frames from a video.
Define a div. Change your picture every x seconds, where x depends on number of images you have made.
You can use the following code for changing image:
function change_background( new_image_source ) {
var myimage = $( '#myimage' );
myimage.attr( 'src', new_image_source );
setTimeout( function () {
change_background( 'new image source here' );
}, 100);
}
This code will change the image after 0.1. This can hopefully give you the required effect but you will need to make a lot of pictures that differ slightly. I would make lots of pictures for my gf (if I had one).

javascript (making collage from images)

javascript code for making collage through images working in mozilla but chrome
$(document).ready(function() {
var canvaswidth = $('.rc-contentholder').width();
var canvasheight = $('.rc-contentholder').height();
function setleftandtop(noofdivision) {
var elements = document.getElementsByClassName('rc-singlecontentholder');
var noofelements = elements.length;
//place the first row
currentelementid = elements[0].id;
$("#" + currentelementid).css('left', '0px');
$("#" + currentelementid).css('top', '0px');
for (j = 1; j < noofdivision; j++) {
previousleft = parseFloat(elements[j - 1].style.left);
top = 0;
previouswidth = parseFloat(elements[j - 1].style.width);
elements[j].style.left = (previousleft + previouswidth) + "px";
elements[j].style.top = 0;
}
//place the remaining rows
for (i = noofdivision; i < noofelements; i++) {
currentid = elements[i - noofdivision].id;
left = parseFloat(elements[i - noofdivision].style.left);
uppertop = parseFloat(elements[i - noofdivision].style.top);
console.log(uppertop)
height = $("#" + currentid).height();
console.log("id" + "=" + currentid + " " + "height" + "=" + ($("#" + currentid).height()));
elements[i].style.left = left + "px";
elements[i].style.top = (uppertop + height) + "px";
}
}
if (canvaswidth >= 1200) {
noofdivision = 5;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth >= 900) {
noofdivision = 4;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth >= 550) {
noofdivision = 3;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth >= 480) {
noofdivision = 2
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
} else if (canvaswidth < 480) {
noofdivision = 1;
singlecontentholderwidth = canvaswidth / noofdivision;
$('.rc-singlecontentholder').css('width', singlecontentholderwidth);
setleftandtop(noofdivision);
}
});
in chrome the height of the division rc-singlecontentholder keeps changing dont know what is happening please help me. Help would be appreciated.
As a rule of thumb you should always provide a standalone example/snippet/jsfiddle, so it is easy for others to figure out exactly what your problem is. In your code the markup(HTML) is missing and several of your variables are not defined. However I will try to give you a push in the right direction from the information you have provided.
I deduced that you want to determine the amount of images your canvas can fit from an element with class 'rc-containerwidth'. The first thing I want to address is that if you iterate from
var j = 0
you can just use
elements[j]
but this is just a minor esthetic.
I am assuming that you have classes called 'rc-singlecontentholder' with actual content, that would make the divs have a width and a height. With this in mind the real problem I see with your code is that the first for loop sets the first n=(noofdivision-1) elements with class 'rc-singlecontentholder' to have top=0.
The second for loop starts at element number n=i-noofdivison. Since it starts at
var i = noofdivison;
this effectively starts at n=0, which means you are looping over the same elements as in the first loop. You then calculate the variable upperTop as the elements top position which will be 0.
upperTop = top = 0;
and finally sets the top of this element as top + height
elements[i].style.top = (upperTop + height) + 'px';
Which will cause the different elements to be positioned at the height of their container. This will happen to the first n=(noofdivison-1) elements and the rest will be placed depending on what your original css for these elements are, which are hard to guess from your question. These factors coupled together is likely what is causing the height in chrome to be different from the height of the divs in firefox. Hope this can point you in the right direction to bandage your code.
There are several improvements that can be done to the code apart from this, but this could be a good task to solve if you are in the stages of learning JavaScript.
If learning JavaScript is not of the essence then I suggest trying to reuse some of the libraries that already exists for image collages, which should be more robust and time-saving than creating your own.
You can check out one alternative called H5P Collage or check out how we used JavaScript to make it at github. Disclosure: I am one of the developers on the H5P team.

Image slider is choppy

I have put together a plain javascript/css image slider, started out as just a learning exercise but am now looking to apply it in the real world. The problem is that the animation is choppy on my desktop (which is a v. high spec gaming rig) - and even worse on a mobile (to the degree it's not really an animation anymore)
You can see it in action here:
www.chrishowie.co.uk/sands/
jsfiddle isolates much of the pertinent code - it's not a "this doesn't work" issue, so hopefully the fiddle gives enough to help optimize it.
http://jsfiddle.net/9aozrxy8/5/
In summary: I have a DIV with 4 images in a row, each image is 100% the width of the page. I use javascript to translateX (I have tried translate3d as heard this uses GPU, but didnt make much diff) and I set CSS transitions to ease-in the transform.
I also thought that potentially I am just trying to do too much on this site - but then I look at some other sites doing a heck of a lot more and it's smooth as silk. So I guess I'm missing something.
function slideRight() {
if (sliding) {
return false
};
window.sliding = true;
el = document.getElementById("slider");
cst = getComputedStyle(el);
transformst = cst.transform || cst.webkitTransform || cst.mozTransform;
widthst = cst.width;
widthst = widthst.replace("px", ""); // computed width of slider (7680px)
slidewidth = widthst / 4;
transformst = transformst.replace("matrix(", "");
transformst = transformst.replace(")", "");
transformst = transformst.split(",");
transformst = transformst[4]; // returns current transform in px without unit (px)
if (!transformst) {
transformst = 0;
}
var activebtn = "sldr" + Math.round((Number(transformst) / (-1 * slidewidth)));
document.getElementById(activebtn).classList.remove("sliderbuttonactive");
if (activebtn != "sldr3") {
document.getElementById("slider" + Math.round((2 + Number(transformst) / (-1 * slidewidth)))).style.visibility = "visible";
document.getElementById("slider" + Math.round((2 + Number(transformst) / (-1 * slidewidth)))).style.display = "initial";
document.getElementById("slider").style.transform = "translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-webkit-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-moz-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-ms-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("leftslidebtn").style.visibility = "visible";
document.getElementById("leftslidebtn").style.display = "block";
}
activebtn = activebtn.replace("sldr", "");
activebtn = "sldr" + (1 + Number(activebtn));
document.getElementById(activebtn).classList.add("sliderbuttonactive");
if (Number(activebtn.replace("sldr", "")) == 3) {
document.getElementById("rightslidebtn").style.visibility = "hidden";
document.getElementById("rightslidebtn").style.display = "none";
}
setTimeout(function () {
window.sliding = false
}, 2000);
}
update: still not resolved but on mobile I have made it usable by reducing the image size for small screens and also not displaying images that are off-screen. Not perfectly smooth but getting there.
Thanks a lot,
C
Like Jeremy mentioned, that the "transition" in your JSFiddle caused the problem, it's also causing it on your website.
In your "Main.css" in line 221. Remove the "transition: top ease 2s;" from class .slide
Everything works fine then on Win8.1/Google Chrome/i7

Categories

Resources