Javascript and DOM manipulation efficiency on RPi Win10 IoT - javascript

Background
I've created a slideshow application with asp.net (C#) and html5/css3/javascript (w/ a bit of jQuery). I'm trying to display this on a Raspberry Pi 2 device running Windows 10 (IoT version) inside the Windows Universal WebView component.
I'm having issues with slides lagging. My slideshow is based off of one div with 3 background images:
The top image is the slide image. Displayed with background-size: contain.
The middle image is a transparent gradient meant to lay over the bottom image for affect.
The bottom image is server generated on image upload and is a zoomed and blurred image meant to give a kind of gradient splash mapping of color hot zones. Any image artifacts left from this process are smoothed by image #2.
Problem
I switch the background image with one line of code:
slide.style.backgroundImage = "url(" + slides[slideIndex % slides.length] + "), " +
"url(../images/egg-shell.png), " +
"url(" + blurred[slideIndex % blurred.length] + ")";
Works great in my browser, however, on the Raspberry Pi the bottom image with middle image overlayed displayed way before the top image.
Abnormalities
I have had to do a couple things to make this work with the Raspberry Pi and Webview component, I only list these because they might be causing my problem:
After changing the background image, I have to set the slide element's display property to none, then back to block to redraw the background image else it won't change.
I'm preloading images by loading a bunch of JS Image objects with paths specified by webservice, then waiting for each image to finish reporting .onload to start the slideshow.
The whole application is pretty lightweight. If needed I can provide it but there must be something simple I'm missing. I don't know the efficiency if I were to load each image in a separate <img> element and then set z-indexs. Nor do I know if the efficiency would increase by letting the images load in separate slides behind the current one. This is why the question is asking about DOM manipulation and Javascript. At any rate, thanks for reading this long explanation and hopefully you can help!

Like this: http://jsfiddle.net/utwqsb45/ or if you prefer
$(function($){
var $slides = $('.slide');
function transition(){
var $current = $('.slide.showing'),
$next = $('.slide[data-number="' + parseInt($current.data('number') + 1) + '"]');
if (!$next.length) {
$next = $('.slide[data-number="1"]');
}
requestAnimationFrame(function(){
$current.removeClass('showing');
$next.addClass('showing');
});
}
setInterval(transition, 1000);
})($);
.slide {
width: 99%;
height: 99%;
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
display: none;
margin: 0 auto;
}
.slide.showing {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="slide showing" data-number="1">one</div>
<div class="slide" data-number="2">two</div>
<div class="slide" data-number="3">three</div>

Related

Background image cut off on Sony Xperia Z1 mobile device

I am building an app that requires a full page background image. I am using Angular JS and CSS3 for the background image.
On page load, the <body back-img> custom directive is hit and runs the following code:
var grindModule = angular.module('grindApp', ['ngRoute'])
grindModule.directive('backImg', function(){
return function(scope, element, attrs){
var url = ['./../static/images/pushup.jpg', './../static/images/work.jpg']
var idx = Math.floor(Math.random() * url.length)
element.css({
'background': 'url(' + url[idx] +') no-repeat center center fixed',
'background-size' : 'cover'
});
};
A random index is generated and then is used to get a random image url from the array that stores them. It then places said url in the following piece of codebackground: url().
Once the page loads the page looks like this:
Notice the black white space at the bottom of the screenshot. I don't want this. This background is working on all devices except this particular phone (that I know of). This bug is only generated when I am using the mobile version of the Chrome browser. It does not happen when I use the mobile Firefox browser. Seems to be Chrome specific, but I could be very wrong.
Here is all of my code if you feel like that could help you: Grind Github.
I had a look at your website.
This is my train of thought:
1) The browser on that mobile could be outdated and is not supporting the "cover" property correctly. But the issue with this is that you've added "center center" as the background position, so, at the worst, the browser -should- be displaying that image aligned at the center of the page by it's center at full scale, which it is not.
2) The fact that the image is not even centered, makes me think that the "body" element is somehow not functioning properly with a height set at 100%. Try adding height 100% to your HTML tag as well.
html,body {
height: 100%;
}
3) If #2 didn't fix it, then I would try and add another element into the page, just after the starting <body> tag like this:
<div class="bg-fullpage-wrapper"></div>
The style for this element should be:
div.bg-fullpage-wrapper {
/* Your current background stuff here ie:
background: url("./../static/images/work.jpg") 50% 50% / cover no-repeat fixed;
*/
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
Remove the height 100% from body tag for this attempt. You'll have to fix z-index of elements when you do it like this.
4) If this DIV doesn't make it work, then I would probably start thinking in terms of browser resources running out etc since the images that seem to load up for me are massive for web format, there might be issues with downscaling from/to that resolution.
This is a CSS issue, not a JS issue. Outside of that, however, I have no idea what's going on behind the scenes.
head {min-height: 100%}
That's all I know.
Reproduced on an Xperia Z2 with Chrome https://developers.google.com/web/tools/chrome-devtools/debug/remote-debugging/remote-debugging

How does Google Doodle work?

How does Google Doodle work?
When i search for it, i found following
Animated Gif
Animated Jpeg Frame. Sprite image will have all frames and this frame is animated using javascript.
Canvas
Which one is correct?
First they enclose the <img> tag JPEG with all the animation frames inside a <div> tag that has a fixed height of 182 pixels and which hides overflow. This creates a fixed window so to speak, which masks all but current animation frame. The image is animated using JavaScript, which changes the top property for the absolutely positioned image to slide it up a fixed interval with the setTimeout() function.
Here is some code of example by Google from one of reference:
<div style="height:182px;position:relative;width:468px;overflow:hidden">
<img border="0" src="source.jpg" id="filmstrip" style="position: absolute; height: 2912px; top: -0px; display: block; ">
</div>
Jquery:
<script>
function naiveAnimation(id) {
var img = document.getElementById(id);
var offset = 0;
var animate = function() {
//slide the image correct frame of animation given by offset
img.style.top = -offset + "px";
//calculate offset to next frame
offset = Math.floor(offset + 182);
//if we are not yet on the last frame...
if(offset < 2912) {
//call me again in half a second
window.setTimeout(animate, 500);
} else {
//at last frame, so all done!
}
};
//start the animation
animate();
}
naiveAnimation('filmstrip');
</script>
I would go for the Animated JPEG and Canvas, although APNG may work too. I haven't seen a 256-bit color image on a doodle. Maybe even a webm. Some doodles have sound and some are interactive, so I think they use whatever they see suitable for their purposes.

How to prevent a background image flickering on change

I'm applying a repeated background image from a canvas to a div via javascript like this:
var img_canvas = document.createElement('canvas');
img_canvas.width = 16;
img_canvas.height = 16;
img_canvas.getContext('2d').drawImage(canvas, 0, 0, 16, 16);
var img = img_canvas.toDataURL("image/png");
document.querySelector('#div').style.backgroundImage = 'url(' + img + ')';
I have to update it quite frequently. The problem is it flickers upon change, it doesn't appear to happen in Chrome but it's really bad in Firefox and Safari. Is it possible to stop this? I didn't think it would happen since it's a dataurl and therefore doesn't need to be downloaded.
Solution:
// create a new Image object
var img_tag = new Image();
// when preload is complete, apply the image to the div
img_tag.onload = function() {
document.querySelector('#div').style.backgroundImage = 'url(' + img + ')';
}
// setting 'src' actually starts the preload
img_tag.src = img;
Try to preload the image resource to the device storage by including the image in DOM like in the following HTML-Code. Maybe the error comes up because the image resource need to be loaded which takes some time (flickering).
<img src="imageToPreload.png" style="display:none;" alt="" />
You may prefer to use sprites-images. By using sprites your application will need less HTTP-Requests to load all ressources into your page. Also add the following CSS styles if you are using css animations. It will prevent background flickering on mobile devices:
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
Preload your image like this, no need to include a <img> with display: none
<link rel="preload" href="/images/bg-min.png" as="image">
Try adding this css to your background element:
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
It should help with flickering..
You can also "force" hardware acceleration by adding this to your background element:
-webkit-transform: translate3d(0, 0, 0);
Another option is to use image instead of DIV and change only the image url.
I struggled with this for a bit, tried preloading, appending the image to the document, etc.
In the end, I resaved the JPEG without the "Progressive" option.
That fixed the rolling flicker when the img src was swapped.
In my case changing height: 1080px; (background height) to height: fit-content;
I think that preloading all the images is essential in any case. What I found is that the way the browsers behave while changing the background image dynamically is different from one another. In Firefox for example it flickers when the change is frequent however in Chrome and Safari it doesn't.
The best solution I came up with so far is drawing the image inside a child canvas that fills the space of the whole parent div.
In all cases, the images you are using must be optimized as it affects the rendering performance.
My javascript code that works now, looks like this
const pic = new Image();
const pic2 = new Image();
pic.src="../images/settings_referrals_anim.gif";
pic2.src="../images/settings_referrals_still.png";
I don't actually reference that code in the query, for example, i use
document.querySelector(".button_Settings_referrals").addEventListener("mouseover", function() {
myDiv.style.backgroundImage = "url('../images/settings_referrals_anim.gif')";
But it seems to work. If I replace the long URL with const pic for example it doesn't work, and if I include the image object declaration and location at first time in the assignment, then the flickering stops.
This does not address all of the specifics noted by the OP, but might be useful for others. Tested in Chrome 97, Firefox 96, Android 11, iOS 15.
I have a div that includes these CSS parameters...
#div_image {
background-image: url( [Path to low-res image] );
background-size: cover;
}
I have a corresponding class that looks like this...
.div_image_highres {
background-image: none !important;
}
The corresponding class has a pseudo-element defined as follows:
.div_image_highres::before {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
content: " ";
background-image: url( [Path to highres image] );
background-repeat: no-repeat;
background-position: 50% 0;
background-size: cover;
opacity: 1;
display: block;
}
I have an img element that also points to the high-res image...
<img id="img_highres_preload" src=" [Path to high-res image ] ">
The img element has a corresponding style which allows the image to be displayed (ensuring that image file loads) but not seen...
#img_highres_preload {
width: 1px;
height: 1px;
}
Two notes: (1) I realize a lot of people use other methods of pre-loading (e.g., programmatically), but I have a personal preference for this method. (2) See the addendum about the reliability of the load event.
Last but not least, I have some Javascript (jQuery) that adds the "high-res" class to "div_image" once the high-res file is loaded...
$(document).ready(function() {
$("#img_highres_preload").off().on("load", function() {
$("#div_image").addClass("div_image_highres");
});
});
This could easily be vanilla JS, but since I use jQuery throughout my code, I like having a consistency.
Here's a summary of what's happening...
Presumably, the low-res image is loaded first and becomes the background image for the div. Even if that does not occur, everything will work as intended (i.e., the high-res image will be displayed).
When the high-res image loads into the img element (i.e., Javascript confirms that the high-res file is loaded), the "div_image_highres" class is applied to "div_image".
As result, the div switches to the high-res image without flashing. In my experience, if anything, it shifts a little to the left; but that often doesn't occur and, if it does, it's not inelegant.
And here's the primary reason I use this approach when required: In my application, there are multiple panels the user can navigate, which results in one panel sliding out of view and the new one into view. If I don't use a pseudo-element (as described above) for displaying a high-res image, the image flickers when its div is hidden and re-displayed. With the above-described technique, I can slide the div in and out of view without any flickering.
Regarding the Load Event
You can't depend on the load event firing. For instance, it typically does not fire when the browser has cached an image. So to make a long post even longer, here's the enhancement I have in my code to accommodate that reality...
I modify the document.ready event (shown above) to look like this:
$(document).ready(function() {
positionOnPage(true);
$("#img_highres_preload").off().on("load", function() {
checkImage();
});
});
checkImage = function() {
var image = $("#img_highres_preload")[0];
if (!image.complete || (typeof image.naturalWidth != "undefined" && image.naturalWidth == 0)) {
console.log("Waiting for high-res image.");
}
else if (!$("#div_home").hasClass("div_home_highres")) {
$("#div_home").addClass("div_home_highres");
$("#img_highres_preload").remove();
}
}
The checkImage function examines the image element to see whether an image has in fact been loaded. In this code example, it is a little redundant — that is, the img element has confirmed the load, so there's usually no need to check it (unless there is some reason to believe the file is being misloaded).
I might do it as shown because I also call checkImage from other places in my code, so if I have more of a programmatic response (unlike the simple version shown), I want all of that code in the same place and written just once. The checkImage function might be called when triggered by a timer or when the section displaying the intended image is about to be displayed. Perhaps something like this...
if (sectionName == "[whatever]" && $("#img_highres_preload").length === 1) {
checkImage();
}
In this example, I look for the presence of the preload img element because I know that my previous function removes the element after it has fulfilled its purpose.
This post has a stripped-down version to illustrate the concept. As written above, it only accommodates a single known img element, so the code could be extended to call checkImage with some parameters (e.g., the name of an image or the element itself) and checkImage could look for the existence of the preload element, so that check occurs in one place. It can be fairly fancy, so I went with the simplest example for this post.
In many cases, this stripped-down version is all I need because typically I only use a high-res photo for a window background image. I either start with the display of a low-res image and switch it out as soon as the high-res file is loaded, or I have some animation that gets triggered after I confirm the presence of the high-res image.
A good case for a more generalized version is when I need a series of images loaded at the outset and don't want to start until all of them are ready. In those cases, the web page might begin with some welcome text that stays displayed until all images have been confirmed.
Hey Guys I know this has been an older question but if you are still flickering after all this you can simply put the final version behind you background div. That flicker is seeing behind the image you currently have so if its the final image it will be smooth.

Using multiple thumbnail sprites with Video.js Thumbnails

I'm trying to use Video.js Thumbnails to display seek-preview thumbnails when hovering over my Video.js player track bar. I have extracted thumbnails from my videos to sprite sheets using ffmpeg. Each sprite sheet holds a set number of thumbnails, and when one gets filled up during thumbnail extraction, a new sprite file is created.
On my video player page, I am using javascript to create an object to load into the thumbnails() function. If I wanted thumbnails for every five seconds, my object may look something like:
th_object = {
0: {
src: 'source001.jpg',
style: {
left: '-40px',
width: '4800px',
height: '45px',
clip: 'rect(0, 80px, 45px, 0)'
}
},
5: {
style: {
left: '-120px',
clip: 'rect(0, 160px, 45px, 80px)'
}
},
...
}
When it is time to change sprite sources (say around 60 seconds of video), I am using the same object:
...
60: {
src: 'source002.jpg',
style: {
left: '-40px',
width: '4800px',
height: '45px',
clip: 'rect(0, 80px, 45px, 0)'
}
},
...
Then I call the thumbnails() function for my video player (called "video" here):
video.thumbnails(th_object);
So, what this is doing is creating a placeholder in my page for the thumbnails and loading the source image and offsetting it, cropping the parts of the sprite that don't need to be shown. But there is only one placeholder being created in the page. For example, an excerpt from my HTML might look like:
<div class="vjs-thumbnail-holder" style="left: 157px;">
<img src="/storage/source001.jpg" class="vjs-thumbnail" style="left: -680px; width: 4800px; height: 45px; clip: rect(0px 720px 45px 640px); visibility: visible;">
</div>
As I move the mouse across the progress bar, the values get updated and my source will eventually change. I am not entirely sure that both images are being loaded on the page, as when I inspect the page elements, there is only one visible at any given time.
When I hover the mouse to a point when a non-first sprite sheet should be loaded as the thumbnail source, the source seems to get stuck. So if I moved the mouse back to a point where the first sprite sheet should be loaded, it won't, and the wrong sprite is displayed for that point in the video.
My first thought is that I need different HTML elements for my sprite sheet sources, but I am new to web development, so modifying the Video.js Thumbnail code this way may not be viable for me. Any help concerning this would be greatly appreciated. If you have any suggestions about other players that incorporate a seek-preview thumbnail display or a better way to accomplish this, those would also be greatly appreciated.
After working with the Thumbnails code for a bit, I discovered a way to get the results I need. The portion of the code that updates the img src for the thumbnails looks like this:
// apply updated styles to the thumbnail if necessary
mouseTime = Math.floor(event.offsetX / progressControl.width() * duration);
for (time in settings) {
if (mouseTime > time) {
active = Math.max(active, time);
}
}
setting = settings[active];
if (setting.src && img.src != setting.src) {
img.src = setting.src;
}
if (setting.style && img.style != setting.style) {
extend(img.style, setting.style);
}
Essentially, I needed to check the current img src against the source source required by the current mouseTime. So I added an extra check that looks like this:
var x = Math.floor(mouseTime / 300);
x = x * 300;
var sourceNeeded = settings[x];
if (setting.src && (img.src != setting.src)) {
img.src = setting.src;
}
if (sourceNeeded.src && (img.src != sourceNeeded.src)) {
img.src = sourceNeeded.src;
}
if (setting.style && img.style != setting.style) {
extend(img.style, setting.style);
}
The hard-coded 300 from above comes from the fact that my sprite sheets contained 300 seconds worth of thumbnails. (Note that in the example in my original post I used 60 instead.) The x variable determines the index in th_object for the proper source location, and if that doesn't match the current img src, I update it. This will allow proper transition from one img src to another as needed.
Hopefully this will help someone in a similar situation in the future.

Robust way to display an image with one fixed dimension

Lets say that we have an image uploaded by the user, the upload script limits the mb but not the image size (so could be any proportion, 600X200,200X350, and so...).
Im already showing this image in one part on my site using the twitter bootstrap image handler written on css, thats good for a profile picture, the problem is that now I want that image to be a cover (like facebook/twitter cover image), my site is responsive so the width of the cover is 900px or 100% if the screen resolution is less than 900px wide. The height is always fixed to 200px. So I know there is a way to control the correct image display using CSS (maybe with jquery too) but Im not a front-end dev, Im a php dev and I dont want to use server side scripts for doing this. So im looking for suggestions or pieces of codes (css, javascript) to start with, I belive that it have to be an already made solution for this, but I dont find any on google. Thanks for any advice!
I would definitely not advise to use a css-only solution. Not even a client-side solution if the uploaded pictures can have any resolution. You want to use a php script to save resized versions of the uploaded images and serve those to the client. Either as a block's background-image and use css (not cross browser) or as an img tag and use js to resize.
css:
.myselector{
background-size: cover;
}
or js (jquery):
$(function(){
var containers = $('.myselector'), w = $(window);
function onResize(){
//resize code
containers.each(function(){
var $this = $(this),
w = $this.width(),
h = $this.height(),
ratio = w/h,
$img = $('img',$this); // assuming there is only one img in each container
$img.css({'width':'auto','height':'auto'});
var iw = $img.width(), ih = $img.height(), iratio = iw/ih;
if(iratio>ratio){
$img.css({
height:'100%',
width:'auto',
marginLeft: (w-iw*(h/ih))/2
});
}
else{
$img.css({
width:'100%',
height:'auto',,
marginTop: (h-ih*(w/iw))/2
});
}
});
}
w.bind('resize',onResize);
//resize on each image load event
$('img',containers).bind('load',onResize);
onResize();
});
Here is a working fiddle : http://jsfiddle.net/kHxd2/2/
The image's onload listener might need tweeking to react when cached images are rendered in IE: http://css-tricks.com/snippets/jquery/fixing-load-in-ie-for-cached-images/
Also you might want to set css rules for rare non-js browsers... (.myselector img{width:100%;})
EDIT : container css:
.myselector{
width: 100%;
max-width: 900px;
height: 200px;
margin: auto; /* centering */
overflow: hidden;
}
see updated fiddle: http://jsfiddle.net/kHxd2/3/
The best solution is to embed the image containers in a main wrapper div and apply the above css rules to that big container.
Here is some useful code to take care of server-side resizing : http://www.9lessons.info/2009/03/upload-and-resize-image-with-php.html
You have to put this image as background-image, and then use style:
background-image: url(url/to/your/image.png);
background-size: cover;
There is a property in css3 called as background-size:cover; and background-size:contain;. You might want to use them to suit your needs.
contain
Specifies that the background image should be scaled to be as large as possible while ensuring both its dimensions are less than or equal to the corresponding dimensions of the background positioning area.
cover
Specifies that the background image should be scaled to be as small as possible while ensuring both its dimensions are greater than or equal to the corresponding dimensions of the background positioning area.

Categories

Resources