Fabric (Canvas) on Mobile Devices while page scroll - javascript

I observed that we are not able to scroll web page by swiping fingers on mobile devices where we have used Canvas linked to Fabric covering full screen.
problem i due to canvase not allowing page scroll how can i fix it.
url : http://dev-shree.com/sendfile/
please check in mobile view.
Is there any way to fix it .
my code for canvase defination :
(function(global) {
"use strict";
var canvas = new fabric.Canvas('canvas',{selection : false,controlsAboveOverlay:true,centeredScaling:true});
var overlayimageurl = $('#myimg').val();
canvas.setOverlayImage(overlayimageurl, canvas.renderAll.bind(canvas));
canvas.stateful = false;

fabricjs canvas class has allowTouchScrolling option Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas
var canvas = new fabric.Canvas('canvas',
{
selection : false,
controlsAboveOverlay:true,
centeredScaling:true,
allowTouchScrolling: true
}
);

What Tim Hill has said is correct. allowTouchScrolling: true, seems to do nothing. If you add pointer-events: none; to upper-canvas and lower-canvas, you can affect the ability to scroll the page while touching the canvas.

pointer-events: none;
will disable other events on canvas

I had the same issue and managed to solve it by implementing the above AND
ensuring all FabricJS objects (upper-canvas, canvas element, lower-canvas) had the CSS;
pointer-events: none;
Hope this helps

If any issue with page scrolling you can use this one in your CSS file :
canvas {
z-index: -1111;
}

If you are using version 2 or higher then you should update the fabric js.
Source: https://github.com/fabricjs/fabric.js/pull/5904/commits/50962efe6bbd77174cda2e9bd169c19d301edb7a
Then use allowTouchScrolling option.
var canvas = new fabric.Canvas('canvas',
{
allowTouchScrolling: true
}
);

All credit to #wnbittle and #alexey-altteam for their answer on the github issue#5903. Worked for me with fabricjs 4.2.0.
Add this function at the bottom of the fabric.js file:
(function(){
var defaultOnTouchStartHandler = fabric.Canvas.prototype._onTouchStart;
fabric.util.object.extend(fabric.Canvas.prototype, {
_onTouchStart: function(e) {
var target = this.findTarget(e);
// if allowTouchScrolling is enabled, no object was at the
// the touch position and we're not in drawing mode, then
// let the event skip the fabricjs canvas and do default
// behavior
if (this.allowTouchScrolling && !target && !this.isDrawingMode) {
// returning here should allow the event to propagate and be handled
// normally by the browser
return;
}
// otherwise call the default behavior
defaultOnTouchStartHandler.call(this, e);
}
});
})();

Related

Chart.js - Responsiveness not correctly working on device orientation change

I have implemented Chart.js into my project which works without problems, but I am experiencing problems while changing the orientation on a mobile device.
If the screen changes from portait mode to landscape everything is resized as expected,
but when changing form landscape to portrait the chart is not being resized... it keeps the width of the landscape-mode.
I am searching for a way to do this without using jQuery-mobile
If someone knows how to handle this (wrong) behavior I would be really pleased to know what to do.
Listen for the orientation change event (in jQuery mobile - $(window).on("orientationchange",function(){ ... });) and trigger a window resize (if you have jQuery this could be as simple as $(window).trigger('resize');
Alternatively, you could replicate the code that executes when the window is resized in the orientation change handler
function () {
// Basic debounce of resize function so it doesn't hurt performance when resizing browser.
var timeout;
return function () {
clearTimeout(timeout);
timeout = setTimeout(function () {
Chart.helpers.each(Chart.instances, function (instance) {
// If the responsive flag is set in the chart instance config
// Cascade the resize event down to the chart.
if (instance.options.responsive) {
instance.resize(instance.render, true);
}
});
}, 50);
};
};
Which is mostly a copy paste of the Chart.js library code, except that I replaced each with Chart.helpers.each
I had the similar problem with mobile gadgets in the different orientation. It was solved using CSS styles. Eg.:
#media (orientation:portrait) {
.chart-container {
min-height: 40vh;
}
}
#media (orientation:landscape) {
.chart-container {
min-height: 90vh;
}
}

html2canvas offscreen

In using html2canvas, I have a stack of DOM objects (relative positioned div's that contain various things), that I wish to create individual thumbnails for. So if there are ten divs, I will create ten thumbnails.
Some of these objects will be offscreen --each of these divs are in a single, encompassing div called "mainDiv". I iterate through the divs within mainDiv and execute the html2canvas on each of them individually.
For those that are onscreen, this works fine. Those that are offscreen do not -- they come back blank. I created a workaround that scrolls the objects to the top of the mainDiv, however this is a kludge and visually unappealing.
Is it possible to specify a DOM object that is not visible? Ideally, I'd like to be able to specify a containing div and have html2canvas ignore the parent visibility, so I can screen capture hidden objects, but barring that, I'd like to be able to screen capture objects that are simply scrolled off screen.
Any thoughts, ideas? Thanks!
---- Here is some example code. Basically, if you had a bunch of divs within a div, iterate through them. I actually do this recursively so that only one gets processed at a time, with the callback calling the recursive function, so it looks something like this:
function recurser(anIndex, callback) {
if (anIndex == -1) {
callback();
return;
}
$(myDivs[anIndex]).html2canvas({
onrendered : function(canvas) {
var img = canvas.toDataURL();
// store the image in an array, do stuff with it, etc.
recurser(--anIndex, callback);
}
})
}
Once the recursive calls are complete, it executes the callback function, which is a function that will do stuff with the images.
Again, all this works fine as long as the objects are visible within the scrolling div that contains all of the divs in #mainDiv. Once any part of the divs are scrolled off, however, they render black. In fact, if half of two divs are scrolled off (the top half of one, the bottom half of the next), they both render completely black.
I know this is an old question but it seemed kind of interesting. Based on my testing it seemed like only position: absolute and position:fixed elements that were outside of the viewport caused this issue. I figured out a solution to the problem.
What I'm doing is making a clone of the element. Setting the styling of the clone to left = 0, top = window.innerHeight (so that it won't be inside the window) and position = 'relative'. Then I append the clone to the body, use html2canvas on the clone, and then remove the clone from the body. This solution works for me in IE, Firefox, and Chrome.
I have created a JSBin example here. Here is the key javascript code:
function hiddenClone(element){
// Create clone of element
var clone = element.cloneNode(true);
// Position element relatively within the
// body but still out of the viewport
var style = clone.style;
style.position = 'relative';
style.top = window.innerHeight + 'px';
style.left = 0;
// Append clone to body and return the clone
document.body.appendChild(clone);
return clone;
}
var offScreen = document.querySelector('.off-screen');
// Clone off-screen element
var clone = hiddenClone(offScreen);
// Use clone with htm2canvas and delete clone
html2canvas(clone, {
onrendered: function(canvas) {
document.body.appendChild(canvas);
document.body.removeChild(clone);
}
});
set 'overflow' as visible for all of its parent elements. After rendered remove it
CSS
.overflowVisible{
overflow:visible !important;
}
JS
$("#container").parents().each(function(ind,elem){
$(elem).addClass("overflowVisible");
});
html2canvas($("#container"), {
onrendered: function(canvas) {
var img =canvas.toDataURL("image/png");
$('body').append(img);
$("#container").parents().each(function(ind,elem){
$(elem).removeClass("overflowVisible");
});
}
});
You can use the latest version of html2canvas. This resolves all images pix-elation issues and rendering object issue. I used the version 0.5.0-beta4 by Erik koopmans refer this and called the html2canvas as below:
$('html,body').scrollTop(0); // Take your <div> / html at top position before calling html2canvas
html2canvas( $("#my_div"), {
useCORS: true,
dpi: 200,
onrendered:function(canvas) {
var str = canvas.toDataURL("image/png");
var contentType = 'image/png';
console.log(str);
b64Data =str;
$('#uploadedImage').val(b64Data); // set image captured by html2canvas
imgFrameSave(); // Call a function to save your image at server side.
}
})
Ah now have you tried Div display: none; and Div display: absolute; (or how you'd like your div to appear - maybe z-index)
arrow1.onclick = (event){
arrow1.style.display = none;
arrow2.style.display = absolute;
}
arrow2.onclick = (event){
arrow2.style.display = none;
arrow1.style.display = absolute;
}
Just use:
{
scrollX: -window.scrollX,
scrollY: -window.scrollY
}
Based on: https://github.com/niklasvh/html2canvas/issues/1878#issuecomment-511678281

iScroll with native scrolling on one axis

I am using the most wonderful javascript tool iScroll4 http://cubiq.org/iscroll-4 on a mobile website for iOS and Android. Here is what my layout looks like:
The horizontally scroll-able area is making use of iScroll4 with the following settings:
var myScroll = new iScroll('frame', { hScrollbar: false, vScrollbar: false, vScroll: false })
The horizontal scrolling part works great. This issue is what happens when a user attempts to scroll up or down the page placing their finger on the horizontal scrolling area. So I need native vertical scrolling, and iScroll horizontal scrolling on the same area.
What I have tried so far:
Removing e.preventDefault() in the iScroll code (allows for native scrolling, but in BOTH axes).
Removing e.preventDefault() and then disabling horizontal scrolling page wide with this:
var touchMove;
document.ontouchstart = function(e){
touchMove = e.touches[0];
}
document.ontouchmove = function(e){
var theTouch = e.touches[0] || e.changedTouches[0];
var Xer = rs(touchMove.pageX - theTouch.pageX).toPos();
var Yer = rs(touchMove.pageY - theTouch.pageY).toPos();
touchMove = theTouch;
if(Yer > Xer){ e.preventDefault(); }
}
which seems to do nothing. How can I allow for native vertical scrolling in the horizontal scrolling area, without loosing the horizontal scrolling of iScroll? I am really stumped here. Thanks in advance.
(just for the record rs(foo).toPos() is a function that makes foo a positive number regardless of its value).
If you would like to achieve the effect described by Fresheyeball without hacking the core, and without changing from iScroll to swipeview, then iScroll 4 does offer you its event listeners to work with.
myScroll = new iScroll('scrollpanel', {
// other options go here...
vScroll: false,
onBeforeScrollMove: function ( e ) {
if ( this.absDistX > (this.absDistY + 5 ) ) {
// user is scrolling the x axis, so prevent the browsers' native scrolling
e.preventDefault();
} else {
// delegate the scrolling to window object
window.scrollBy( 0, -this.distY );
}
},
});
By doing so, the onBeforeScrollMove-Handler checks whether the scroll direction seems to be horizontal, and then prevents the default handler, thus effectively locking the scroll action to the X-Axis (try commenting it out, you'll see the difference). Otherwise, if the scroll direction needs to be vertical, we make the browser scroll via the window.scrollBy() method. This is not exactly native, but does the job just fine.
Hope that helps
Lukx
[EDIT]
My original solution, which didn't use window.scrollBy() ,did not work on slower Samsung phones, which is why I needed to adapt the answer.
Suggested edit to #Lukx's excellent solution. New versions of iScroll4 place the e.preventDefault() in onBeforeScrollMove which can be overridden. By placing the if block into this option, default is not prevented for vertical scrolling, and vertical can scroll natively.
myScroll = new iScroll('scrollpanel', {
// other options go here...
vScroll: false,
onBeforeScrollStart: function ( e ) {
if ( this.absDistX > (this.absDistY + 5 ) ) {
// user is scrolling the x axis, so prevent the browsers' native scrolling
e.preventDefault();
}
},
});
With iscroll 5, you can set eventPassthrough: true to achieve this. See http://iscrolljs.com/#configuring
OLD ANSWER
UPDATE a special pluggin has been written just to address this problem:
http://cubiq.org/swipeview
I found a way!
add a variable to the top of the document: if android is 15 and is iOS is 3
var scrollTolerance = ( rs().isDevice('android') )?15:3;
disable the original e.preventDefault(); for scrolling. This is under onBeforeScrollStart:
the in _move just under
timestamp = e.timeStamp || Date.now();
add this line
if( Math.sqrt(deltaX*deltaX) > scrollTolerance){e.preventDefault();}
What this does is the following:
the scrollTolerance sets, you guessed it, a tolerance for finger direction. We don't want to demand a perfect vertical angle to get the up down native scroll. Also iOS does not detect properly and will never be higher than 4 for some reason so I used 3. Then we disable iScroll's standard e.preventDefault(); which prevents native vertical scrolling on our bi-scrollable area. Then we insert e.preventDefault(); only upon move and based on finger direction from tolerance.
This does not work perfect. But is acceptable and works on iOS and Android. If anyone sees better ways please post here. This is something I (and assume others) need to use regularly, and we should have a perfect rock solid solution.
Thanks.
Please test this solution from Adam.
https://gist.github.com/hotmeteor/2231984
I think the trick is to add the check in onBeforeScrollMove. First get the initial touch position in onBeforeScrollTouchStart and then in onBeforeScrollMove check the new position and then disable the required scroll based on the difference.
iScroll 5 supports native scrolling of any axis!
http://iscrolljs.com/
on iScroll5 just set eventPassthrougt to true. That fixes it.

jQuery drag left/right

I've just created a custom carousel with images and have got previous/next arrows to move the images around.
Does jQuery have an event where I can click on the photo, drag it to the left or right and fire the same action that I currently have on the arrows?
My current code looks like this
$carousel.animate({
left: '+=' + amountToAnimate
}, 800, 'backEaseOut');
I also need to prevent Firefox from 'picking' the image up.
I'm already using jQuery UI if that helps.
You will need to add draggable() to your item and add some custom code the start event.
With more sample code it might be easier to give fuller advice, jsfiddle.net sample is best
EDIT:
You could use events api http://api.jquery.com/category/events/ , mousemove and mousedown, to figure which way to move the image, and call the animate event.
Re-using draggable , with some clever options and event functions may be better
I also need to prevent Firefox from 'picking' the image up.
Use the Mozilla CSS Extensions
-moz-user-focus:ignore;
-moz-user-select:none;
might to do the trick.
This may not be the most elegant solution but I believe it should do the job
// shortcut
var j = jQuery;
// add mouse down listener to the image
j('#image_id').mousedown(function(){
// add mouse move
j('#image_id').mouseMove(function(event){
// declare vars
var previous_x_position;
var previous_y_position;
if(x_position)
{
previous_x_position = x_position;
previous_y_position = y_position;
}
var x_position = event.pageX;
var y_position = event.pageY;
if(previous_x_position < x_position)
{
// we are moving right
}
else
{
// we are moving left
}
if(previous_y_position < y_position)
{
// we are moving down
}
else
{
// we are moving up
}
})
})

html5 canvas hand cursor problems

I'm playing around with html5 and some javascript to make a minor sketchpad. Whenever I click down on the canvas in chrome, the cursor becomes a text cursor. I have tried putting cursor: hand in the css, but that doesn't seem to work. This has got to be an easy thing, but I look it up and can't find it anywhere
Use the disable text selection on the canvas. This works like a charm.
var canvas = document.getElementById('canvas');
canvas.onselectstart = function () { return false; } // ie
canvas.onmousedown = function () { return false; } // mozilla
Cheers,
Kris
While the other guys were absolutely bang on referring you to the quirksmode reference, that won't fix the problem you are having, and essentially you need to implement a variation of Kris's answer.
In my own implementation, I found that preventing default behaviour in the mousedown event was all that was required to stop that pesky text selection cursor:
function handleMouseDown(evt) {
evt.preventDefault();
evt.stopPropagation();
// you can change the cursor if you want
// just remember to handle the mouse up and put it back :)
evt.target.style.cursor = 'move';
// rest of code goes here
}
document.addEventListener('mousedown', handleMouseDown, false);
Hope that helps.
Cheers,
Damon.
Use pointer for your cursor property instead, like this:
canvas { cursor: pointer; }
hand is IE/Opera specific, you can see a full list of which cursors work in which browsers here.

Categories