I have been doing a fair bit of research and reading into the following scenario:
Scenario:
User touches the screen in such a way as to pinch-to-zoom in on the canvas element.
Canvas element now takes up 100% of the width and height of the viewport after zooming.
User is now unable to unzoom or remove themselves from this state without hitting the back button. Pinch-to-zoom is consumed by the canvas.
The design specifications for our web application necessitate the ability to pinch-to-zoom on the page housing the canvas. As such, the suggested best practice of disabling user-scalability on the tablet is not applicable to my scenario.
Is it conceptually possible to bubble the multi-touch "pinch-to-zoom" event up from the canvas element to the browser/tablet?
Are there other, less-obvious solutions I should consider other than:
Invisible div overlay on the canvas. Disable all user-interactivity, but support pinch-to-zoom.
Somehow provide a way of unzooming that doesn't involve a gesture so that the user can escape from the scenario outlined above.
Related
We are facing the following challenge: We are creating a behavioral experimentation library, which both needs to be able to show random shapes as well as display forms.
For the shape drawing part we use pixi.js, and even though we know it can also use canvas2D, we prefer it to use WebGL as its rendering engine, which uses the 3D context of the canvas. Pixi however doesn't really have the ability to draw form elements on the canvas, so we decided to use Zebra/Zebkit for this, but zebra can only draw to 2d context.
According to many sources, it's impossible to use 2D and 3D context simultaneously with a single canvas, or switch from 2D and 3D context (and vice versa) after the canvas has been initialized. We therefore decided to create 2 separate canvases, one with a 3D context to use with Pixi.js, and one with a 2D context to use with Zebra/zebkit. When necessary, we switch the canvases by showing one and hiding the other.
This works quite well when the canvases are integrated in the web page, but less optimal when we want to display the experiment fullscreen. It is very difficult to switch from one canvas to the other in fullscreen, because you can only choose one DOM element at the time to be displayed full screen, and weird stuff happens when you start hiding the full screen element to show another. My question is: what would be the best approach to tackle this problem? I already have several in mind:
Put both canvases in a container div, and display this container fullscreen instead of the canvases itself. I don't know if this is possible, or if this will have any negative side effects compared to showing a canvas in fullscreen directly.
Render the zebkit canvas on top of the pixi canvas by making sure it is on top of the overlay item, as suggested in How do I make a DIV visible on top of an HTML5 fullscreen video?. This situation seems very hacky though, and I smell inconsistency issues between the various browsers that are around already.
Use the method described in How do I make a DIV visible on top of an HTML5 fullscreen video? to render normal HTML form elements on the pixi canvas. I predict there will be some resolution/rendering problems to tackle though, because you don't have the degree of control over the pixel raster as you have with canvas items.
I've already read all the stuff around scrolling:
Structuring an HTML5 Canvas/JS Game
and so on:
HTML5 Canvas tutorial
The secret to silky smooth JavaScript animation
Google search "HTML5 Scrolling"
Canvas Games
Build a vertical scrolling shooter game with HTML5 canvas
Math mayem
CAAT JavaScript framework
(The latest one is impressive, but even though almost everything is done there's nothing about scrolling).
Here's what I'm thinking about, and I didn't found something valueable about that. An idea just came to my mind and I'm wondering if I should take a lot of time thinking about that and trying, or not (that's why I'm asking here actually).
I'm planning to do a game with a scrolling "à la" Mario.
The big drawback about scrolling is that you have to redraw the whole background.
I've already avoided two performance problems of the sprite / scroll: create two canvas one top of each other:
the background
the sprites
And just erase the sprites.
The problem is about the background: I'm making a full copy of the background to the "visible" canvas. (note: there's no problem about flickering because writing in JavaScript is a blocking operation and all modern browsers handle vertical synch, so no double buffering needed).
Here's an old version of what I'm writing, but you'll get the big picture:
Test HTML5
Now I'm wondering for the scrolling: what if I do a "background div" instead of a canvas, with the appropriate CSS (background image for the background), and write the tiles on the image directly, then change CSS to simulate the scrolling? Should it be faster? If so, why? Is there any good idea out there for this?
On a semi-modern+ computer with a semi-recent+ browser, the fastest thing to do is probably to take a super-long div with background images, set overflow to hidden and scroll by adjusting scrollLeft or scrollTop properties. This is MUCH faster than adjusting CSS properties as it shouldn't trigger any reflow calculation in the CSS engine. Basically, any time you touch a DOM property that could have CSS impact, the whole (or at least a lot of) of) the structure of the document needs to be re-checked and re-rendered.
You could load in chunks of the backgrounds as they get close to avoid the one giant massive image load. I don't believe there is any 100% surefire way to pull an image out of memory across browsers but removing references to it in the DOM or in your CSS probably doesn't hurt when you've scrolled far enough past a piece of your background. That way the browser's garbage collector at least has the option of clearing memory.
In pan-mobile solutions that rely on webviews (like Cordova/Phonegap), however, well that's why I arrived at this question.
I have no idea but I'm pretty sure mixing HTML and canvas is a lousy idea for performance purposes. Right now I've got a not-super-complicated android game choking on 50x50 100px tiles in a canvas element in an android web view that also has some basic HTML in the mix for stuff like controls and separating a couple other canvas elements from the rest. I basically have a birds-eye-view ship cruising around and doing scans with a cheesy radiating circle grahic that reveals elements on a map fog-of-war style. Works great in a browser. Complete disaster in the cordova app version.
I suspect the only way I'm going to realize my pan-mobile game dev dreams is to use one of the many openGL-wrapped-in-a-canvas-API solutions out there and completely ditch the HTML which I find damned convenient for UI implementation, given that the bulk of my experience is in web UI. Another general tip for web view HTML is to avoid scrolling within internal elements if you can (so just let the body handle overflow). Scrolling overflow in anything but the body didn't even work in Android 2's webviews and it still seemed to cause 4.1's views to choke on an earlier/simpler version of the app I'm working on.
My final conclusion: after many tries, including Eirk Reppen suggestion, I write directly "raw" into hidden parts of the canvas and use CSS: all webbrowsers handle already image flickering and all that stuff around, and they have already optimized everything.
So each time I've tried to "optimize", the results were worse.
It seems that webbrowsers are made to handle properly basic stuff made by beginnners... maybe because 99% of HTML content is made by beginners.
Here is a demo of scrolling an oversize canvas by changing the CSS margin, this one based on scrolling with time: https://jsfiddle.net/6othtm0c/
And this version with mouse dragging: https://jsfiddle.net/ax7n8944/
HTML:
<div id="canvasdiv" style="width: 500px; height: 250px; overflow: hidden">
<canvas id="canvas" width="10000px" height="250px"></canvas>
</div>
JS for the scroll-with-time version:
canvas = document.getElementById("canvas");
context = canvas.getContext('2d');
for (var i = 0; i < 1000; i++) {
context.beginPath();
context.arc(Math.random() * 10000, Math.random() * 250, 20.0, 0, 2 * Math.PI, false);
context.stroke();
}
var t0 = window.performance.now();
setInterval(function(){
canvas.style.marginLeft = -(window.performance.now() - t0)/5 + "px";
}, 5);
fastest scrolling is to scroll using CSS. So you draw all background once, not only visible part, but all, and hide that is not visible, and use css to scroll it (margin, or position). No redraw, only CSS changes. This work really fastest. But if all map is really huge, other custom ways can be better.
Is there any way to be able to query the GPU to tell me if my viewport in my webpage is currently on screen or not? For example, if I had a 3d scene rendering in a canvas in an iframe, is there a way to query the hardware (within my iframe and only the pixels or verts in the viewport) to say if I am on screen or scrolled off screen?
I'm curious as to whether this is something I can do at the vertex shader level. Does WebGL even perform the shader program on a viewport that is offscreen? Lets say if it is scrolled below the canvas, or the viewport is obstructed by another webpage browser window? Is there a way to query the compositing portion of webgl to see if it is even in view or Iterate through the "RenderObject" Tree to test if it is even onscreen and then return this value? I am trying to get much more performance out of a project I am working on and I am trying to only render what is visible on screen.
Any possible ideas? Is this even possible? Thanks!
RequestAnimationFrame is only reasonable way to handle unnecessary performance loss even semantically because window.requestAnimationFrame tells the browser that you wish to perform an animation... So browser will figure out how it should handle your wish in optimal way taking into account current page state.
But since iframes communicate using local storage you can push to them your base page state so each of them will decide should it RequestAnimationFrame or not. But im not shure that it is a good thing to have multiply render contexts on your page, they all eat resources and can't share them (data that stored in GPU is sandboxed) so eventually they will start to push each other from GPU memory and cause lags + GPU pipeline might be not so happy with all those tiny standalone entities. Fragmentation is main GPU performance enemy.
You don't ask this question at the canvas/WebGL level, because it might, for example, be scrolled back on screen before you draw another frame, and browsers don't want to not have content to show, so there's no provision to not draw.
I believe you will have to consult the DOM geometry properties (e.g. .scrollLeft) of your scrollable areas to determine whether the canvas is visible. There is enough information in said properties that you can do this generically without hardcoding knowledge of your page structure.
Also, make sure you are exclusively using requestAnimationFrame for your drawing/simulation scheduling; it will pause animations if the page is hidden/minimized/in another tab/otherwise explicitly invisible.
I'm interested in writing lots of HTML5 apps for devices with e-ink (bistable) screens.
But bistable screens exhibit a lot of strange and disconcerting visual artifacts whenever the screen contents change, especially when the browser is drawing and redrawing the layout when a page is loaded or when some javascript modifies the DOM.
So.... is there any way for my HTML code to tell the browser and its operating system to hold off on redrawing anything on the screen until it's done figuring out the new layout?
It is probably a dirty hack, but you could think of putting a full page opaque white div on the top layer - and then remove it with javascript once the page is fully loaded
Bit of background
I've been producing a Flash-driven webcomic for three years now, incorporating some basic animation, a synced soundtrack and zoom-drag page viewing. The recent Flash-bashing, my desire to reach iHandhelds and my preference for open versus proprietary means that I want to make the move to HTML5 techniques this year. In the long-term, I think the writing's on the wall for Adobe's product, and I'm not entirely convinced that's a bad thing.
I'm relatively comfortably with both CSS and HTML, having worked a little in web design before. However, JavaScript is a foreign country to me, and I simply wanted to get some advice as to
whether what I want to achieve can be accomplished consistently across all browsers and
what the best techniques/approaches to the problem would be.
Any advice, even general principles, are very welcome. I've already sought out several HTML5 tutorials and introductions, which lead me to believe that the canvas element will be foundational to my plan; however while all the individual problems I face have been answered by many blogposts and guides, combining the various solutions into a single entity is something I'm not currently able to figure out, as I'm not certain of the limitations of the new HTML5 tags, or of best practice.
If I'm successful in achieving what I'm after, I'm going to post the full code online with an explanation of all the elements. Webcomics might not be a huge domain, but having a resource that did this would have made my life a lot easier - hopefully it'll help someone else in a similar position.
What I'm after
Here's a diagram giving the basics of the design requirements. I'll explain the elements, and the desired extras, below.
(Perhaps the simplest way to demonstrate what I'm after would be for interested folks head over to my website and see how my comic currently works. This isn't a plug - it would simply give the quickest insight.)
At core, I'm after a viewer that will:
display text (SVG image) in a canvas element above an raster image the page's panel art
both images should be zoom-and-draggable in sync but should ideally fade in separately, with the raster image coming first, followed by the SVG image
I'm guessing that the best way to accomplish this would be to layer two canvas elements one above the other using z-index, with the SVG file in the uppermost element. These could then be nested, as in the diagram, within a div element that would carry the zoom-drag function. Is this a reasonable approach, or are there more efficient options?
The next and previous buttons are self-explanatory. Would it best to have each page (bearing in mind some will involve animation and music) on a separate page, or to have all pages within a chapter on a single page, with the buttons making them visible progressively? I imagine this would have a great impact on loading speeds.
Finally, I'd like to have the viewer capable of displaying fullscreen if the reader desires. I imagine this could be accomplished by using Javascript to make the canvas elements and their surrounding div switch between different CSS giving a px-defined size and 100% height and width. Is this a good approach? Is it possible to apply the size change to the div element only and have the canvas elements automatically follow suit, possibly by defining their size via % in CSS?
Desired extras
At various points in the comic I make use of basic animation techniques - simple movements of layered raster images across the viewing pane. This would be simple to accomplish, I imagine, using Javascript; am I correct in thinking that applying overflow:hidden to the wrapping div will prevent images larger than the viewing area from spilling outside the viewer area?
I also want to synchronise audio with some of these animations. I understand that synchronising canvas events with the audio would be the best way to do this on, permitting both to begin activity only upon page loading or next button click.
That's about everything. As said, any advice at whatever level would be greatly appreciated, even if it's 'yes' or 'no' to the various questions I've asked. At root, it would also be good to know if HTML5 is the best option for what I'm after or whether (with gritted teeth) I should stick to Flash for now and go after handhelds using Adobe AIR.