I am building a HTML5 magazine for tablets and desktops with use of swipe.js (http://swipejs.com).
Everything seems to work fine, In one HTML page I have set next to each other fullscreen list elements. The whole magazine is build up in one static html file. I can slide through the pages by swiping on tablets, and by using buttons for the desktop version (consider the example on the swipe.js homepage, but then with fullscreen slides).
The pages are placed next to each other, and have the dimensions of the screen.
[ |0||1||2| .. |i-1||i||i+1| .. |n| ]
The swipe.js transitions are done with help of css3, using the translate3d() css function. In this case, hardware rendering is used.
On desktop (Chrome, Safari, FF), iPad1 and (even better on) iPad2 this has the desired effect I was looking for; smooth transitions. Perfect!
However, on the iPad3, the pages seem to render 'slow' when entered (by transition) for the first time. Even without setting background images (just the color), the 'rendering' of the transitioned page is considered a little 'slow'; the page is build up by 'flickering' blocks.
Assumption:
My assumption is (after reading into the subject), that this is because the browser only renders the elements that are in-screen, and will cache the swiped pages only for a while, cleaning the cache afterwards to control memory management.
My question: Is there a way to control the offscreen rendering and caching, so that I can force (pre) render page elements i-1, i+1 (and flush the cache for all other page elements), to speed up my transition rendering?
Note: In several topics on StackOverflow, 'flickering' of css3 transitions is mentioned. I have implemented the suggested CSS tricks but will not solve my case.
-webkit-backface-visibility: hidden;
-webkit-transform:translate3d(0,0,0);
In the end the solution was a hack of Swipejs in which I added a method 'hideOthers()', setting the style visibility to 'hidden', which unloads the pages from hardware memory:
hideOthers: function(index) {
var i = 0;
var el;
for( i in this.slides ) {
el = this.slides[i];
if ( el.tagName == 'LI' ) {
// Show pages i-1, i and i+1
if ( parseInt(i) == index
|| (parseInt(i) + 1) == index
|| (parseInt(i) - 1) == index
) {
el.style.visibility = 'visible';
}
else {
el.style.visibility = 'hidden';
}
}
}
}
..and added the trigger below as last line in the 'slide()' method
// unload list elements from memory
var self = this;
setTimeout( function() { self.hideOthers(index); }, 100 );
Only the translate3d was needed to toggle the hardware acceleration on (as mentioned in my question above):
-webkit-transform:translate3d(0,0,0);
You can find the result (including iScroll for vertical scrolling) here.
in regards to the webkit backface/translate3d props used to trigger hardware acceleration, I've read that in iOS 6+ these don't work quite the same as in previous versions, and (more importantly) that hardware acceleration needs to be applied not only on the element that is being animated, but also on any element that it is overlapping/overlaps it.
reference (not much): http://indiegamr.com/ios6-html-hardware-acceleration-changes-and-how-to-fix-them/
To be fair this is fairly anecdotal, I was myself unable to fix my own flickering issue - due to tight deadlines - but this might be a point in the right direction.
Related
I'm using a bootstrap 3 fluid grid to display thumbnails, and I love how the images scale in size as the browser is resized. The downside however, is a "big bang" effect when each page is loaded. That is, the grid begins collapsed then grows as images are added. I imagine a simple fix is to hardcode image sizes, but this would lose the scaling benefit I believe.
One attempt to fix this was to load a transparent placeholder image right before each thumbnail, which would of course be cashed on the first page of results and thus expand the grid faster. On callback for thumbnail loaded event, I remove the placeholder. This seems to help, but other times I still see the shifting as badly as before. In addition, with a slow connection you can actually for a moment see the real thumb below the placeholder.
<script type="text/javascript">
$(function(){
// For each thumbnail, insert a placeholder image.
// Once the thumb is loaded, remove the placeholder.
$("[id^=thumb-]").each(function(i, thumb) {
var $thumb = $(thumb)
var imgTag = "<img id='ph-" + (i + 1) +
"' class='placeholder' src='{% static "img/placeholder.png" %}'/>";
$thumb.parent().prepend(imgTag);
var $holder = $thumb.prev();
function loaded() {
$holder.remove();
}
if (thumb.complete) {
loaded();
} else {
$thumb.on('load', loaded);
$thumb.on('error', function() {
console.log('Error with thumbnail placeholders.');
});
}
});
});
</script>
Regarding compatibility, I'd like to at least have a usable site with older browsers, but it doesn't have to be perfect.
I'm not as interested in fixing my Javascript solution above as I am the best solution overall.
Please look at the live beta site here to help diagnose. I attempted a jsfiddle, but couldn't quite reproduce it. I will paste more context into the question once we understand what was wrong.
In this case, I would recommend adding the <img> tag to the plain HTML. Then set the src in your javascript function.
You'll also need to set height and width attributes on the <img> tags so their space is preserved, to prevent redrawing the page after the images are loaded. You could do this with a simple javascript function that determines the window.width and then sets the height and width attributes.
Something like this.
This is an Android app that uses WebView to display a long list. The long list's visibility can be toggled by the following JS function:
function _showOverlay() {
$("#container").css("visibility", "visible");
}
function _hideOverlay() {
$("#container").css("visibility", "hidden");
}
a style recalculation is triggered by both function. On desktop the performance is fine but on slower phone device (Galaxy Nexus class), the performance is not acceptable. Anyway to speed this operation up? or, any other trick I can use to show/hide a div?
Tried the following:
"opacity:0" - can't use this because the list can still respond to user touches while invisible (bad)
"display:none" - triggers same style recalculation.
I have a SVG chart using d3js. We can add some points to this chart and move it. When I have a big page and so when we need to scroll it, it works with the mouse. But I have an input screen with multi-touch and in more I develop my app for mobile.
The input with the chart and the scroll aren't working together with an input touch. For example if I want to move my point it's the page which scroll and not my point wich move. It's not exactly the same bugs on firefox, IE and my Windows RT app.
You can see a little example here to test if you have an input touch, I guess tablet and smartphone will have the same behaviour than my PC with a touch screen.
I have the following css to simulate a bigger app:
body {
overflow:visible;
width: 2000px;
height: 2000px;
}
There is a way to do this?
I hope you understood my problem :)
I tested this on my phone and tried to research how to force a browser to stop scrolling with little success. The good news is your app allows a mobile user to place a new point really nicely.
To get the project done quick, you might need to create a set of controls that grabs an id of each existing point and allow the mobile user to move the desired point using buttons. The UI for such a set of controls could be minimal and intuitive if done well. You could set the UI to display:none and only show when the screen width/height is iPad size or less.
I finnaly found a solution with the pointer-events property in css
var C1 = document.getElementById("C1"),
evtIn = window.navigator.msPointerEnabled ? "MSPointerDown" : "touchstart",
evtOut = window.navigator.msPointerEnabled ? "MSPointerUp" : "touchend";
C1.addEventListener(evtIn, function () {
d3.select("#C1").style("pointer-events", "all");
d3.select("body").style("overflow", "hidden");
}, false);
C1.addEventListener(evtOut, function () {
d3.select("#C1").style("pointer-events", "none");
d3.select("body").style("overflow", "auto");
}, false);
On touch start I just allow pointer events in my chart et disable overflow and in the other way for the touch end.
I am a newbie to javascript programming, but am making progress! I am developing a web app in house for children with autism, for touch screen browsers (55" touch screen PCs and Nexus 7 tablets). We will only use Firefox as it appears most compatible. The children will click on image "buttons" to make choices and to communicate their needs. The buttons need to give visual feedback when touched. I have solved this by using the active state in CSS:
img { opacity:1.0 };
img:active { opacity:0.4 };
This works fine. Hover is no good for use on touch screens. I also have a need for some images to be made invisible but to remain where they are, and to toggle on and off on a long press. For this I have found a toggle function and a timer function and combined them.
JAVASCRIPT (in <head> of page):
var t
function tog_vis(id) {
var e = document.getElementById(id);
if(e.style.opacity == 1 )
e.style.opacity = 0 ;
else
e.style.opacity = 1 ;
HTML:
<img id="myimg" onclick="DoSomething();" onmousedown="t=setTimeout(function(){ tog_vis('myimg'); }, 1500);" onmouseup="clearTimeout(t);" src="images/img1.png">
Problem is the active state gets taken over by the onmousedown and onmouseup events (I have read that this is because they are both part of the click event - makes sense!), and I am guessing that the onclick event may also mess things up further.
Expected/Desired behaviour:
1.On a normal click, the image changes opacity to 0.4, and when released returns to 1, then completes the onclick request.
2.On a long click, the image opacity goes to 0, and on a second long click the opacity returns to 1, with NO onclick event.
The app will eventually have # 100 similar images that must perform the first behaviour, whilst the second behaviour will only be needed on # 10 buttons so I could happily code functions individually if necessary. I have also found that the 55" touchscreens (Windows 7) are not responding to the img:active CSS, so guessing these are relying on the touchdown and touchup events, whilst the tablets are very well behaved.
Any help here much appreciated.
Tim
You could you css3 transitions and a little javascript for this use case. Have a look at this fiddle: http://jsfiddle.net/Ce8J5/
Also you could realise the hover with javascript/jquery, just remove the hover css statement and define some addionatial css classes and add them via javascript.
E.g.
$("#element").mouseenter(function(){
$(this).addClass(".hover");
});
$("#element").mouseleave(function(){
$(this).removeClass(".hover");
});
My page didn't require a horizontal scroll bar initially, but now one appears mysteriously that is beyond any of the elements that are covered on inspect on Chrome and firebug. No elements pass that blue line so I'm not sure how to fix this.
I know I can hide the scrollbar with overflow-y:hidden, but that's not the point. It shouldn't be there at all.
EDIT Here's the jsfiddle: http://jsfiddle.net/S8RUp/
A bit messy, but I think it gets the point across.
The jsFiddle link has too many overflowing contents to be useful. What you can do to ease debugging is to use a bit of code like this to show you only elements that are over a threshold width:
// using jQuery - you can use other library or include it temporarily for debugging purposes
$('*').each(function() {
var w = parseInt($(this).width(), 10);
// you can put something larger than 700, depending on your situation
if (w > 700) {
console.log(w, this);
}
});
It will have a few false positives (the html node for example), but you'll probably find the culprit easily enough.