Using hammer js with a canvas - javascript

I have a little problem using Hammer JS with my canvas.
I explain ;
I have a canvas defined like this :
<canvas id="myCanvas"></canvas>
In this canvas, i add some Img :
var s = new CanvasState(document.getElementById('myCanvas');
s.addImg(new Img(100, 0, data.image, data.identifiant));
And , i would like to use Hammer JS to rotate my new Img.
For this, i tried something like :
var hammertime = new Hammer(document.getElementById('myCanvas'));
hammertime.on('pan', function(ev) {
console.log(ev);
});
hammertime.get('pinch').set({ enable: true });
hammertime.get('rotate').set({ enable: true });
I don't know what i should put instead myCanvas. I tried something like myCanvas.selection (the IMG OBJECT) but in vain ..
Any idea ? Any person who already used Hammer JS with a canvas on which we have elements / objects ?
Seems hammerJS don't recognized Objects ..
Thanks

You can use Fabric.js library. It is canvas library, that helps you interact with it much easier. Point is - hammerjs in working very nicely with Fabric.js.
All you need to do, once you have inicialized Fabric.js is this:
const hammertime = new Hammer(canvas.upperCanvasEl);
hammertime.get('pinch').set({ enable: true });
hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL });
hammertime.on('pan', (ev) => {
alert("pan!");
});
Please note, if you want to enable pinch gesture, you need to enable it.
"canvas" is Fabric.js initialized canvas element.
"upperCanvasEl" is generated by Fabric.js and intercepts all events. Please note, if you use TypeScript that this property is not yet supported by it, so you need to cast it to "any".

Related

How to recreate canvas in multiple divs?

I have test poll and there are a lot of charts which i need to clean before redrawing them. I was looking for solution and the only one i found was to recreate canvas. So i was trying to remove them all (removing works fine) then recreate, but for some reason all canvas got created on the first div (#chart-center) only.
Here is the code i was using:
$(".test-question").each(function () {
$('canvas').remove();
$('#chart-center').append("<canvas></canvas>");
});
Any thoughts? Thanks in advance.
Your solution would be to delete them step by step and find the inner canvas and replace it there.
$(".test-question").each(function () {
$(this).find('canvas').remove();
$(this).find("#chart-center").append("<canvas></canvas>");
});
You should also never use the same id's: use classes instead!
Another solution would be to clear your canvas like this:
$(".test-question").each(function () {
let canvas = $(this).find("canvas").get(0);
let c = canvas.getContext('2d');
c.clearRect(0,0,canvas.width,canvas.height);
});

Creating "Tools" in FabricJS?

I am working on a simple editor where you can move text, pictures, and pretty much anything around. It's nothing too complicated, however I am having an issue choosing between using PaperJS and FabricJS - The main reason being the ability to natively transform items (rotate, scale, etc.).
Even though I love PaperJS, I am really considering moving to FabricJS. I create tools for PaperJS like this:
function shapeTool(options) {
this.tool = new Tool();
var options = $.extend({
shape: "circle",
}, options);
this.tool.onMouseUp = function(event) { ... }
...
...
this.tool.activate();
return tool;
}
This is probably the worst way to create them, but for me it's easy to throw all these functions in a file and init my tools: var tool = new shapeTool(options);
Since I will possibly be moving to Fabric, what is the easiest way to make modular tools. In which I can swap between them? (i.e. I have a toolbar and when i click a button my tool changed so i can freedraw, insert images, etc)
Clarification: When I mean a tool, I am talking about a tool in PaperJS. IN Paper, we are able to swap the canvas's active tool. The tool would handle the current mouseDown, KeyDown, etc. events for the canvas. I could write different tools for things like inserting shapes and images, and write one for freedrawing. I could then set the active tool to either one. This would allow me to swap between freedraw and inserting shapes.
Thanks,
Hunter M.
In FabricJS you interact with the behaviour of mouse with events.
Cavas fires:
mouse:down
mouse:move
mouse:up
mouse:over
mouse:out
You register events with ON and OFF:
canvas.on('mouse:down', handler);
You have just on predefined state that is drawingMode true or false
canvas.isDrawingMode = true;
And free drawing starts.
When not drawing the mouse down and up or move can be customized by a property you add to canvs.
canvas.myState = 'addStamps';
Then in your handler:
handler(e) {
switch (canvas.myState) {
case 'deleteItems':
e.target && canvas.remove(e.target);
break;
case 'addStamps':
canvas.add(new fabric.Image('stamp.jpg'));
break;
}
}
You have to do same for mouse:up or mosue:move if you need interaction other than clicks.
This is one of the many ways you can obtain a similar effect.

scroll zoom on two images

I have two images with same dimensions and same positions, but placed in divs with dynamic width depending on user interaction using the jquery beforeAfter plugin.
I would like to enable scroll zooming on these images using wheelzoom, such that zooming on one of these images will zoom the same amount in the same position as the other.
What I am unable to do is this linking of (I suppose) the event handlers along the lines of this:
function onwheel(e){
//adjust image to fit zoom level ...
other_img.onwheel(e);
}
If this is not possible, is it possible to copy the event and change the target image?
I am looking for a solution using either jquery or native Javascript.
Code here (ignore the handle).
EDIT: Any top-level pointers to what should work would also be appreciated
I made a worked example: http://plnkr.co/edit/kH0ec8TVMXUIYlMoBaMq?p=preview
here is the core code:
document.getElementsByClassName("before")[0].addEventListener("wheel", function(event){
if(flag){
flag= false;
return;
};
flag=true;
var newEvent = new WheelEvent("wheel",event);
var elementToTrigger = document.getElementsByClassName("after")[0];
elementToTrigger.dispatchEvent(newEvent);
});
I do something simple, when an event happening("wheel") a trigger the same event to another element and pass as argument the data from the first event to the new event. I use flag variable to deter the custom event trigger again the other event and start an eternal loop.
This is a solution without to edit the source code of plugin. You can do more good solutions if you change the code of wheelzoom.js.
Make the zooming a function that takes enough parameters to handle zooming, and get the values you need from the event handler.
function handleZoom(domNode, zoomDirection, zoomAmount) {
// Do stuff to change the size of `domNode`
}
var img1, img2;
img1 = /* select image node */;
img2 = /* select image node */;
function handleScroll(scrollEvent) {
var direction, amount;
// Use `scrollEvent` to figure out which direction and how far to zoom
handleZoom(img1, direction, amount);
handleZoom(img2, direction, amount);
}
img1.onscroll = handleScroll;
img2.onscroll = handleScroll;

How to Manipulate Image After Uploaded To Canvas (FabricJS)

I've been racking my brain on this for a while now, but I can't seem to rotate the image on Canvas after uploading. Here's the code sample in question:
// INITIATE & DRAW CANVAS
var canvas = new fabric.Canvas('CanvasArtArtboard');
// CREATE OVERLAY GRIDS
canvas.setOverlayColor('rgba(205, 173, 64, 0.6)', canvas.renderAll.bind(canvas));
// UPLOAD USER IMAGE TO CANVAS
document.getElementById('imgLoader').onchange = function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function () {
// start fabricJS stuff
var image = new fabric.Image(imgObj);
image.set({
originX: 'left',
originY: 'top',
padding: 0,
cornersize: 10,
scaleX: 0.4,
scaleY: 0.4,
});
//image.scale(getRandomNum(0.1, 0.25)).setCoords();
canvas.add(image);
image.sendToBack();
canvas.renderAll();
//end fabricJS stuff
}
}
reader.readAsDataURL(e.target.files[0]);
}
// ROTATE UPLOADED IMAGE
$("#angle-control").click(function(){
var curAngle = canvas.item(0).getAngle();
canvas.item(0).setAngle(curAngle+15);
canvas.renderAll();
});
I've looked at the following example:
Add image from user computer to canvas (Stack OverFlow Question)
http://jsfiddle.net/PromInc/3efe2x9j/
Once the user uploads their image and clicks the "rotate 90*" button, I'm looking for the image to then rotate.
EDIT: Apologies, here is my JSFiddle in it's current state: http://jsfiddle.net/darnellcreates/oq6htzew/3/
I had a look at your fiddle and there is a lot wrong. The code for rotating is ok (sort of) but the page is full of problems.
First there is no JQuery and you are using the JQuery $ function as selector to access DOM elements. I do not see the point in using jQuery if all you are doing is using it as a selector, you use document.getElementById in some parts and $ in others. This totally negates any benefit Jquery would provide.
Second you are duplicating DOM element ID's (This is a strict no no) DOM ID's must be unique to the page.
To get you on your way here are a few changes,
Change the slider element in the HTML to
<input type="range" id="angleControl1" value="0" min="-90" max="90">
Note that the id is unique to the page. I have also avoided the naming convention (did not make it angle-control1) as this is a simple page and I will take some shortcuts and access the DOM elements directly in JavaScript.
Next remove the click handler for the range slider and replace it with a mouse move event listener.
// keep a copy of the last value so there is no needless rotates
var lastValue = angleControl1.value; // no need to search the node tree.
// you can access elements directly by
// their ID.
// Listen to the mousemoves of the range control. Click, change will
// only update at the end of the mouse down up process. This does not
// provide good user feedback
angleControl1.addEventListener("mousemove",function(){
if(this.value !== lastValue){ // only update the angle if it has changed
// set the angle to the absolute angle rather than relative as you had it
canvas.item(0).setAngle(Number(this.value)); // Number() is me being pedantic
canvas.renderAll(); // rerender
lastValue = this.value; // remember the last value
}
}); // all done for this function
Note. Direct DOM element access can be problematic in some situations (if you duplicate ID's, use that id as a variable before the DOM has loaded, your page is sharing the global namespace, or someone is using an old netscape browser) but for simple pages it is the easiest and safest way (If someone has netscape they can't run the page anyway because there is not canvas element).
Also remove the other Jquery calls $() as they cause the page to crash and stop everything from running.
You need to use the DevTools in these types of situations. It will show you all the errors and give you warnings (FireFox) for bad habits. To access the DevTool hit f12 on most browsers.The DevTools console will list errors and provide a link directly to the code where it is happening. You can also step through the code line by line so you can see what is going on.
i updated your jsfiddle ,to work both the rotate button 90o and the range bar,
just in case you need it.
link: http://jsfiddle.net/rqevmp3y/1/
$("#angle-control").on('click', function (event) {
console.log('rotate');
var curAngle = canvas._objects[0].getAngle();
canvas._objects[0].setAngle(curAngle+90);
canvas.renderAll();
});
$("#rangeControl").on('change', function (event) {
console.log('rotate from range',$(this).val());
var curAngle = canvas._objects[0].getAngle();
canvas._objects[0].setAngle(curAngle+parseInt($(this).val()));
canvas.renderAll();
});

jQplot tooltip dismiss issue

I have implemented a simple bar chart,
ive added tooltip feature using highlighter but i am facing an issue with the same.
When i move the mouse down and exit the chart canvas the tooltip doesnt dismiss
I have tried adding
$.jqplot.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
$.jqplot.eventListenerHooks.push(['jqplotMouseLeave', handleMove]);
But it doesnt work , i get the error handleMove is not defined
Here is the code fiddle for the same
https://jsfiddle.net/9j2na3L7/
I finally got this working :)
-- PROBLEM:
Mouse cursor escaping too fast from canvas, prevents event form fireing
-- SOLUTION:
First of all grab a handle of jplot object
var plotBar = $.jqplot('task_brk_bar_chart', [...
So we can use it to manipulate it on run-time.
Then we will use jqplotDataHighlight and jqplotDataUnHighlight events to change the graph properties and replot() function to apply them on fly.
$('#task_brk_bar_chart').bind('jqplotDataHighlight', function () {
plotBar.showTooltip = true;
plotBar.replot();
});
$('#task_brk_bar_chart').bind('jqplotDataUnhighlight', function () {
plotBar.showTooltip = false;
plotBar.repolot();
});
Working fiddle : https://jsfiddle.net/urahara/9j2na3L7/1/
Note: Copy your old css to override my setting, it was for testing purposes only.
Cheers!

Categories