I’m having a problem here since a couple days ago with Google Chrome. I love pixel art and I'm trying to create a huge animated map using html5.
Everything was ok until I started to use more than 5 or 6 canvas at same time.
In Firefox and Internet explorer the map has no problems, but in Chrome the CPU reaches 70% and sometimes even more.
Can you give me some good tips about how solve this kind of issues in Chrome?
I've been searching on Internet about improve performance in Chrome but nothing is helping me.
Thanks for your help.
Just for reference this is the map:
http://pixelslivewallpaper.github.io/jadsdsengine/Zelda.htm
Solution:
The easy way to fix this problem is stopping the animation of all the canvas outside the user visible area and resuming them later. The way for calculate this area is capturing the scroll position.
Apparently, Firefox and Internet explorer are doing this job automatically, but in Google Chrome you need do it manually.
Here is the code:
this.loadIsVisibleOptions = function () {
if (this.stopAnimationWhenIsNotVisible) {
window.addEventListener("scroll", function (event) { currentJadsdsEngine.isVisible(document.getElementById(canvasID), currentJadsdsEngine) });
}
}
this.isVisible = function (element, obj) {
if (element.offsetWidth === 0 || element.offsetHeight === 0) {
currentJadsdsEngine.stop();
}
else {
var rects = element.getClientRects();
var result = false;
var tempClientHeight = document.documentElement.clientHeight;
var tempClientWidth = document.documentElement.clientWidth;
for (var i = 0, l = rects.length; i < l; i++) {
if (rects[i].top + rects[i].height > 0 ? rects[i].top <= tempClientHeight : (rects[i].bottom > 0 && rects[i].bottom <= tempClientHeight) == true) {
if (rects[i].left + rects[i].width > 0 ? rects[i].left <= tempClientWidth : (rects[i].right > 0 && rects[i].right <= tempClientWidth) == true) {
result = true;
break;
}
}
}
if (result) {
currentJadsdsEngine.resume();
}
else {
currentJadsdsEngine.stop();
}
}
}
Inspiration:
How do I check if an element is really visible with JavaScript?
Related
It has been my experience that with Edge that the "target" received by your IntersectionObserver callback has been set to the newly scrolled-in element rather than (like Chrome and Firefox) where it still reflects the element that started scrolling-out. I played with smaller thresholds but sadly my function thinks the scroll snap fell short and don't bother changing the current image marker dot.
I'm looking at separate issues with Firefox as well :-(
Apart from waiting 'n' nanoseconds after a scroll event is there a better way to know where your carousel is at?
Guess I'll just take the "IF" out and see if I can fix FF.
EDIT: Firefox only seems to allow me to observe 2 elements for my intersection observer. Do I have to new-up a separate IntersectionObserver object for each element being observerved?
carousel = document.getElementById("carousel");
let observerOptions = {
root: carousel,
rootMargin: "0px",
threshold: [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
};
bannerObserver = new IntersectionObserver(imageScrolled, observerOptions);
for (let i = 0; i < 5; i++) {
bannerObserver.observe(document.getElementById("d" + i));
}
function imageScrolled(divContainers) {
divContainers.some(function (imgContainer, containerIndex) {
let targetDiv = imgContainer.target;
if (imgContainer.intersectionRatio > 0.5) {
if (targetDiv.dataset.imgId != currDot) {
clearTimeout(bannerLoop);
dots[currDot].style.backgroundColor = "";
currDot = targetDiv.dataset.imgId;
dots[currDot].style.backgroundColor = DOT_COLOR;
bannerLoop = setTimeout(scrollBanner, bannerInterval);
return true;
}
}
});
}
The IntersectionObserver is currently too unreliable/inconsistent so I went for a simple onscroll event: -
function onTheMove(e) {
for (let i=0; i < e.srcElement.children.length; i++) {
if (e.srcElement.scrollLeft == e.srcElement.children[i].dataset.imgId * e.srcElement.children[i].clientWidth) {
if (e.srcElement.children[i].dataset.imgId != currDot) {
clearTimeout(bannerLoop);
dots[currDot].style.backgroundColor = "";
currDot = e.srcElement.children[i].dataset.imgId;
dots[currDot].style.backgroundColor = DOT_COLOR;
bannerLoop = setTimeout(scrollBanner, bannerInterval);
break;
}
}
}
}
caniuse.com is wrong on this one :-(
Im trying to make an infinite loop for a carousel when i click a desired div it will be centered at a desired position, if i click the item that is adjacent to the centered position, everything works fine, but if he is more than 1 position away from the center it triggers an effect that doesnt follow the usual logic.
I have tried to solve the problem by checking the distance from the center and than moving the items 1 by 1 n times, but i guess because the loop doesn't wait for the animations to finish im getting this weird effect.
The final outcome should be making an infinite feel to the carousel when you click an item that is 5 positions away from the center it would center it and the ones that are out of view will slide from the respective direction to create a loop
any help will be appreciated, Im relatively new to web dev so a well explained answer will be highly appreciated
JS:
const serviceList = document.querySelectorAll('.service__block');
serviceList.forEach(service => {
service.addEventListener('click', () => {
markSelectedService(service);
moveService(checkDistance(service));
});
});
//Adds the class to the clicked service
function markSelectedService(service) {
removeSelectedClass();
service.classList.add('selected');
}
//Removes the selected class from all the services
function removeSelectedClass() {
serviceList.forEach(service => {
service.classList.remove('selected');
});
}
//Check distance from center
function checkDistance(service) {
let distance = service.dataset.order - 4;
return distance;
}
//Move the service 1 by 1 n times
function moveService(distance) {
if (distance > 0) {
for (var i = 0; i < distance; i++) {
serviceList.forEach(service => {
service.dataset.order = parseInt(service.dataset.order) - 1;
if (parseInt(service.dataset.order) === -1) {
service.dataset.order = 11;
}
});
}
} else if (distance < 0) {
distance = distance * -1;
for (var i = 0; i < distance; i++) {
serviceList.forEach(service => {
service.dataset.order = parseInt(service.dataset.order) + 1;
if (parseInt(service.dataset.order) === 12) {
service.dataset.order = 0;
}
});
}
}
}
Link to codepen:
https://codepen.io/tomyshoam/pen/yLLLYyQ
If you want to wait for the animation's end to trigger the next one you insert a setInterval and set the interval time to your animation's time.
Example:
var i = 0;
var animationInterval = setInterval(function () {
//YOUR LOGIC HERE
if (++i === distance) {
window.clearInterval(animationInterval);
}
}, 500);
Update
After some tries I think I got it working how you wanted, although it's not the better way to do it.
I copied the icons list, one to the right side and one to the left, this way the icons will only move to the other side when they are far far away from the user's view and will not trigger that weir behavior.
Code below:
https://codepen.io/diogoperes/pen/oNNNBGY
Im trying to finetune the controls of a javascript game (p5 library).
keyIsDown() is the type of control/feel im looking for but it's timing is too fast.
By timing is too fast, I mean when I hold down the key, the key repeats too fast. Im trying to control the timing speed of the key repeat when holding down the key.
I tried to make my own vertion with keytyped() and setInterval to time my move function. Then stopping it with keyReleased(). But it jams up.
I have also tried setTimeout but could not get it to work on keyboard input like this.
var controlInterval;
function keyReleased() {
if (key === 'a') {
clearInterval(controlInterval);
} else if (key === 'd') {
clearInterval(controlInterval);
}
//return false; // prevent any default behavior
}
function keyTyped() {
if (key === 'a') {
controlInterval = setInterval(left, 50);
} else if (key === 'd') {
controlInterval = setInterval(right, 50);
}
}
function left(){
var x = -1;
move(x);
}
function right(){
var x = 1;
move(x);
}
code I prefer to use:
if (keyIsDown(LEFT_ARROW)){
var west = -1;
move(west);
}
if (keyIsDown(RIGHT_ARROW)){
var east = 1;
move(east);
Take a look at debouncing and throttling principles which I think is what you are looking for here - limit the execution count of event.
The best explanation IMHO related to this subject is this article.
There are already libraries to help you like lodash. Go to their documentation page and search the functions - debounce or throttle and it there will be examples how to use them.
someDiv.addEventListener('keyup', _.debounce(handleKeyUp, 300));
function handleKeyUp(event) {
if (event.keyCode === 65 /* A */) left();
...
}
Arrow keys can be used to signal a direction, frame rate can be used to control speed and a delta variable used to control the amount of movement.
var xPos = 0;
var xDelta = 1;
function setup(){
createCanvas(200,200);
frameRate(10); // 10 frames per second, increase to move faster
}
function draw(){
background(100);
if (keyIsDown(LEFT_ARROW)){
var west = -1;
move(west);
}
if (keyIsDown(RIGHT_ARROW)){
var east = 1;
move(east);
}
rect(xPos, 100, 10,10);
}
function move(dir){
if (dir == -1){
xPos = xPos - xDelta;
}
else {
xPos = xPos + xDelta;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js"></script>
I'm using this to get a smooth scroll to a particular section when a user clicks on a button:
window.scroll({
top: $(this).data('y'),
left: 0,
behavior: 'smooth'
});
This works great everywhere (including Android phones) but on Safari (desktop and iphone). In those cases it scrolls to the correct position but it isn't smooth, it's like it jumps.
I made a small demo on Codepen available here. Just click on the nav menu options and it will scroll there. This will be smooth on Chrome but not on Safari.
Is this not supported? (it doesn't seem to be the case looking at the doc) What are the supported options?
Thanks!
window.scroll is supported, but scroll-behavior CSS is not.
https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior
Pending support, consider using the smoothscroll-polyfill which adds smooth scrolling support for Safari, IE, and Edge.
I recently wrote down my ideas into a function, which is kind of polyfill for lacking smooth scroll feature support in IOS browsers and desktop Safari as well. Some may call it a bloody workaround, but hey, it's working. It doesn't require jQuery, it's pure javascript.
var fnc_scrollto = function(to,id){
var smoothScrollFeature = 'scrollBehavior' in document.documentElement.style;
var articles = document.querySelectorAll("ul#content > li"), i;
if (to == 'elem') to = articles[id].offsetTop;
var i = parseInt(window.pageYOffset);
if ( i != to ) {
if (!smoothScrollFeature) {
to = parseInt(to);
if (i < to) {
var int = setInterval(function() {
if (i > (to-20)) i += 1;
else if (i > (to-40)) i += 3;
else if (i > (to-80)) i += 8;
else if (i > (to-160)) i += 18;
else if (i > (to-200)) i += 24;
else if (i > (to-300)) i += 40;
else i += 60;
window.scroll(0, i);
if (i >= to) clearInterval(int);
}, 15);
}
else {
var int = setInterval(function() {
if (i < (to+20)) i -= 1;
else if (i < (to+40)) i -= 3;
else if (i < (to+80)) i -= 8;
else if (i < (to+160)) i -= 18;
else if (i < (to+200)) i -= 24;
else if (i < (to+300)) i -= 40;
else i -= 60;
window.scroll(0, i);
if (i <= to) clearInterval(int);
}, 15);
}
}
else {
window.scroll({
top: to,
left: 0,
behavior: 'smooth'
});
}
}
};
You may pass arguments to the function as numeric value (scollTo-position in pixels) or as a call of an element with index (in my case LI nodes in an UL --> "articles").
<a class="active" href="javascript:fnc_scrollto(0)">Home</a>
<a class="active" href="javascript:fnc_scrollto(457)">anywhere</a>
element 1
element 2
You may play around with the numbers to adapt the smooth effect to your needs.
If you have a sticky navbar on top, you need to adapt the line
if (to == 'elem') to = articles[id].offsetTop;
to your needs like e.g.
if (to == 'elem') to = parseInt(articles[id].offsetTop-navbar.clientHeight);
Hope you like it :-)
More specifically in a JavaScript context, the unsupported part is the behavior parameter on scrollToOptions as detailed here:
https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll
THis is my code gist.
Leap.loop({enableGestures: true}, function(frame) {
var gestures = frame.gestures;
for (var i = 0; i < gestures.length; i++) {
// I want to do something when draw circle with one pointable
if (gesture.type == "circle" && gesture.state == "stop" && gesture.pointableIds.length == 1) {
var isClockWise = ? ;// how to know the direction of circle ?
}
}
} );
How to know circle is clockwise or counter clock wise with gesture object ?
I was using leap motion only 2 days and really need your help.
Leap.loop({enableGestures: true},function(frame) {
var gestures = frame.gestures,
circle,
pointable,
direction,
normal;
// Check if is there any gesture going on
if(gestures.length > 0) {
// In this example we will focus only on the first gesture, for the sake of simplicity
if(gestures[0].type == 'circle') {
circle = gestures[0];
// Get Pointable object
circle.pointable = frame.pointable(circle.pointableIds[0]);
// Reset circle gesture variables as nedded, not really necessary in this case
if(circle.state == 'start') {
clockwise = true;
} else if (circle.state == 'update') {
direction = circle.pointable.direction;
// Check if pointable exists
if(direction) {
normal = circle.normal;
// Check if product of vectors is going forwards or backwards
// Since Leap uses a right hand rule system
// forward is into the screen, while backwards is out of it
clockwise = Leap.vec3.dot(direction, normal) > 0;
if(clockwise) {
//Do clockwose stuff
} else {
//Do counterclockwise stuff
}
}
}
}
}
});
Looking on the C++ sample given on the leap website, piece of code is given to detect is the circle is clockwise.
C++ code :
if (circle.pointable().direction().angleTo(circle.normal()) <= PI/4)
{
clockwiseness = "clockwise";
}
else
{
clockwiseness = "counterclockwise";
}
I haven't used the Javascript API, but I think this can be something equivalent
This code hasn't been tested, but in Javascript it may be something like :
// considere your gesture is a circle, and there is at least one pointable object.
if (gesture.type == "circle" && gesture.state == "stop" && gesture.pointableIds.length >= 1)
{
var dir = frame.pointables[gesture.pointableIds[0] ].direction; // get direction of the Pointable used for the circle gesture
var angle = dir.AngleTo (circle.normal);
var isClockWise = angle <= (3.14 / 4);
}
Got all infos from Leap JS API from GitHub and Leap Motion Developers site
-> Be careful frame.pointables return pointables objects given in arbitrary order.(Cf JS API doc). This piece of code is just for the explanation of the algorithm
This is the easiest way to find out
var isClockwise = (circleGesture.normal[2] <= 0);
It will return true or false
Tried other answers on this page and couldn't get it to work, simplified the code a bit and finally got it working. The pointableID logs normal as negative/positive based on direction of the circle gesture.
function pageScrollDown() {
window.scrollBy(0,10);
};
function pageScrollUp(){
window.scrollBy(0,-15);
};
$(window).bind('circle', function(e, gesture){
var circle = gesture;
circle.pointable = circle.pointableIds[0];
direction = gesture.normal[1];
if(direction < 0 ) {
pageScrollDown();
} else {
pageScrollUp();
}
});
I have been using the "Leap Cursor library" for my project and it is really cool. Identifying a circle gesture on a element is very simple with this library.
var circleTrackElements = document.querySelectorAll(".myDOMElements");
for (var i = 0; i < allTiles.length; i++) {
circleTrackElements[i].addEventListener("leap-circle-stop", function(e) {
console.log("CIRCLE DETECTED");
});
};
LeapManager.init({
maxCursors : 1,
interactiveSelector : ".myDOMElements"
});
GITHUB link for the library