How to hide the overflow of photos in canvas? - html

I am trying making a photo frame pattern on canvas. In which I want to put two, three or maybe more photos under an overlay frame. Where few parts of the overlay frame are transparent.
If I upload photo1 into first section of frame its visible into second section also and uploading photo2 into section two is also visible into first section. Depending on which photo is uploaded first or edited at last is overlapping the other photo.
I want to know how to hide the overflow of photo so it should not be visible into other sections. How can I achieve this?
I have done this so far:
canvas.on({
'object:moving': onChange,
'object:scaling': onChange,
'object:rotating': onChange,
});
function onChange(options) {
options.target.setCoords();
canvas.forEachObject(function (obj) {
if (obj === options.target)
return;
if (obj.id != 'cover1' && obj.id != 'cover2')
return;
if (options.target.intersectsWithObject(obj)) {
// Hide this portion
canvas.renderAll();
}
});
}
Kindly provide me the best solution

You need to apply a clipTo() method onto the image.
var canvas;
$(function(){
canvas = window._canvas = new fabric.Canvas('canvas');
var radius = 200;
fabric.Image.fromURL('http://fabricjs.com/assets/pug_small.jpg', function(img) {
img.scale(0.5).set({
left: 250,
top: 250,
angle: -15,
clipTo: function (ctx) {
ctx.arc(0, 0, radius, 0, Math.PI * 2, true);
}
});
canvas.add(img).setActiveObject(img);
});
});
This fiddle show the technique
Fiddle

Related

Capturing and saving objects coordinates with fabric js

I am working on an app where a user can create multiple boxes on a canvas, save the coordinates of each box(Top, Left, Width, Height) individually in database, and later retrieve them back on a canvas, whenever needed to update its position.
I am able to do all this, except updating the position of the box.
For eg. Lets say user selects "box1":
1) canvas.on('mouse:down', function (evt) { }); - gives the current coordinates for box1, that matches with the database entry.
2) canvas.on('object:modified', function (evt) { }); - gives the new coordinates for box1, that I can use to update the database fields.
The only problem is, if the user selects box1, drag it some where, drops it, and again drags it to a new position. I loose the original value (since he clicked mouse:down twice for box1), and thus not able to finally identify, which box was updated wrt database.
Below is the code snippet:
window.addRect = function() {
var box = new fabric.Rect({
left: 0,
top: 0,
stroke: 'red',
fill: 'rgba(255,0,0,.4)',
width: 50,
height: 50,
});
box.hasRotatingPoint = false;
canvas.add(box);
}
canvas.on('object:modified', function (evt) { // for updated values
var modifiedObject = evt.target;
console.log('modifiedObject: ' + modifiedObject.get('left'), modifiedObject.get('top'), modifiedObject.getScaledWidth(), modifiedObject.getScaledHeight());
});
canvas.on('mouse:down', function (evt) { // for original values
var downObject = evt.target;
console.log('downObject: ' + downObject.get('left'), downObject.get('top'), downObject.getScaledWidth(), downObject.getScaledHeight()); });
Is there anything other than mouse:down and object:modified, that I can use? I am looking for a solution in Extjs.

KineticJS - How to Change Image src on Button Click

I'm trying to change the src of an image in my kineticjs stage on a button click.
I have a draggable image (in this case darth-vader) and a static image on top (in this case monkey). On the click of a button i want to be able to replace the draggable image with a new one (yoda)
JSFiddle can be seen here:
http://jsfiddle.net/SkVJu/33/
I thought the following:
btn.addEventListener("click", function (event) {
mainImage.src = path+'yoda.jpg';
layer.removeChildren();
draw(mainImage,true);
draw(foregroundImage,true);
});
would accomplish it: first by updating the src, then removing all objects and redrawing both again in the correct order.
For some reason though i get 2 yoda images placed on the stage - 1 correctly behind but another above everything else...
Instead of removing all the children and adding them back, you can swap image sources easily by using the KineticJS setImage function and passing in a Javascript Image Object: http://kineticjs.com/docs/Kinetic.Image.html#setImage
I updated your draw function so that it takes an id and name so that we can select the Kinetic Image object later:
// Draw function
function draw(image,drag,id,name){
if (typeof id == 'undefined') id = '';
if (typeof name == 'undefined') name = '';
var img = new Kinetic.Image({
image: image,
draggable: drag,
id: id,
name: name
});
layer.add(img);
layer.draw();
return img;
}
and then here is your update click function:
// Change draggable Image
btn.addEventListener("click", function (event) {
layer.get('#mainImageId')[0].setImage(mainImage2); //get the object with id "mainImageId"
layer.draw();
});
jsfiddle
Also, I moved your foregroundImage load function inside the mainImage onload function so that we make sure the Monkey is added to the stage after the mainImage:
// Define draggable image
var mainImage = new Image();
mainImage.onload = function () {
draw(mainImage,true, 'mainImageId');
// Define foreground image
var foregroundImage = new Image();
foregroundImage.onload = function () {
draw(foregroundImage,false);
};
foregroundImage.src = path+'monkey.png';
};
mainImage.src = path+'darth-vader.jpg';
Wouldn't it be easier to load both images right away, create new Kinetic.Group of them, set one visible and other hidden, than just create function that will hide first and show second on click? Just asking cause i have similar issue to deal with, just that in my case exchange should be done among 5 different icons based on settings parameter that user can change...

How to integrate a progress bar into angularjs directive with file upload

I need to create a progress bar for file uploads. I know my progress event listener is working. Is there are more "angular way" to be doing this? How can I update the progress bar from inside my event listener?
As a preface, please feel free to correct and critique the general logic flow if it too needs help.
I have this canvas...
<canvas id="progress"></canvas>
I have an angularjs directive that uploads files. I added a progress event listener (only showing relevant parts)...
link: function postLink(scope, element, attrs, ctrl) {
var fileUpload = function (img, file) {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function(e) {
if (e.lengthComputable) {
var percentage = Math.round((e.loaded * 100) / e.total);
// UPDATE THE PROGRESS BAR HERE
}
}, false);
}
element.bind('change', function (evt) {
var files = evt.target.files;
var canvas = document.getElementById("progress"),
context = canvas.getContext("2d");
context.fillStyle = 'lighgray';
context.fillRect(0, 0, 200, 18);
context.moveTo(0, 0);
context.fillStyle = 'darkgray';
context.fillRect(0, 0, 1, 18);
for(var i = 0; i < files.length; i++) {
fileUpload(files, files[i]);
}
}
}
Have a look at Angular UI Bootstrap: http://angular-ui.github.io/bootstrap/
It provides directives for Bootstrap UI elements including the progress bar.
It looks like you'd just have to bind the upload progress value with the bar, and it will automatically update.
(Gotta love two-way data binding.)
take a look at HTML5 progress tag, your code will look like
if (e.lengthComputable) {
var percentage = Math.round((e.loaded * 100) / e.total);
$('progress').val(percentage);
}
I do know it has many problems with compatibility and it looks different in different browsers (though you can fix it using css3: nice example)
in your case you should fill rectangle again and again
if (e.lengthComputable) {
var percentage = e.loaded / e.total;
context.fillRect(0, 0, progressWidth*percentage, 18);
}
I get rid of *100% because you'd better use var progressWidth = 200 when you create context
look this example, it shows better what I mean (and sorry for my English)

Canvas on Chrome Mobile not working after rotation

Trying to fix a really annoying problem that I'm having. I have an HTML5 canvas that I'm allowing users to draw on, which is loaded in an iframe. When the page first loads, it checks to see if we're on a mobile device and, if so, it resizes the whole page, including the iframe. I then have a setTimeout that runs every few seconds to check and see if my canvas is a different size from the frame it's loaded in. If it's different, I change the canvas size and then reinitialize it (using Kineticjs 1.0, I know there are newer versions but we're not ready to upgrade).
This works in most of the mobile browsers that we test, but Chrome (on iOS and Android) doesn't allow drawing on the canvas either when the page is first loaded in portrait or after an orientation change. It just scrolls the page (standard touch event) and ignores all of my preventDefaults. I can't even get it to do an alert on touchstart after the orientation changes.
Has anyone run across this before? I'm thinking it's either something with the fact that the canvas itself is changing or that maybe once the new stage(canvas) is created in Kinetic all of the defined listeners become ignored.
Update:
Here's some of the code I'm dealing with:
// This page is loaded in a frame, so we check to see when the parent is loaded
parent.$(document).ready(function()
{
$(document).ready(function()
{
ut();
setTimeout('start_orientation_detect_timer()','2000');
});
});
function start_orientation_detect_timer()
{
if(document.getElementById("data").value.length == 0 && Math.floor(canvas.width) != Math.floor(parent.$(parent.top_origin.frame_array['sig_block_frame']).width()) || Math.floor(canvas.height) != Math.floor(parent.$(parent.top_origin.frame_array['sig_block_frame']).height()))
{
if(top_origin.misc_variables.mobile_device !== false && top.window.orientation == 0)
{
parent.$('#flip_to_landscape_msg').show();
parent.$('#flip_to_landscape_msg').effect("pulsate", { times:200 }, 2000);
}
else
{
parent.$('#flip_to_landscape_msg').stop(true, true);
parent.$('#flip_to_landscape_msg').hide();
}
ut();
}
else
{
// so from this frame several deep, we need to know the orientation, which will only be in the top of the DOM
if(document.getElementById("data").value.length == 0 && top_origin.misc_variables.mobile_device !== false && top.window.orientation == 0)
{
parent.$('#flip_to_landscape_msg').show();
parent.$('#flip_to_landscape_msg').effect("pulsate", { times:200 }, 2000);
}
else
{
parent.$('#flip_to_landscape_msg').stop(true, true);
parent.$('#flip_to_landscape_msg').hide();
}
}
setTimeout('start_orientation_detect_timer()','2000');
}
function ut()
{
canvas=document.getElementById("drawing_canvas");
context = canvas.getContext("2d");
//console.log(Math.floor(parent.$(parent.top_origin.frame_array['sig_block_frame']).width())+' '+Math.floor(canvas.width)+' '+Math.floor(parent.$(parent.top_origin.frame_array['sig_block_frame']).height())+' '+Math.floor(canvas.height));
canvas.width = parent.$(parent.top_origin.frame_array['sig_block_frame']).width();
document.getElementById('saved_layer').style.width = canvas.width;
canvas.height = parent.$(parent.top_origin.frame_array['sig_block_frame']).height();
document.getElementById('saved_layer').style.height = canvas.height;
myStage = new Kinetic.Stage(canvas);
canvas.onmousemove = function()
{
var mousePos = myStage.getMousePos();
var mouseDown = myStage.getMouseDown();
if (mousePos!=null && mouseDown)
{
draw_b(mousePos.x, mousePos.y);
}
else
{
new_segment = true;
}
};
canvas.ontouchstart = function()
{
BlockMove(event);
}
canvas.ontouchmove = function()
{
var mousePos = myStage.getMousePos();
console.log(mousePos);
if (mousePos!=null)
{
draw_b(mousePos.x, mousePos.y);
}
};
canvas.ontouchend = function()
{
new_segment = true;
};
myStage.listen();
}
function BlockMove(event)
{
// Tell Safari not to move the window.
event.preventDefault() ;
}
I know some of this isn't the most updated code, but it does work except for on Chrome mobile. I've gotten it to the point where if I do not call the start_orientation_detect_timer then the canvas is only about 100px wide by 210 tall, but I can draw on it in Chrome mobile. It seems that once the canvas is stretched, I can't draw anymore. Not even a larger canvas with bigger strokes, nothing happens and the touchstart isn't triggered.

Flickering on mouse-over on multiple elements

I'm creating an interactive app allowing people to customise doors. To allow them to select the letterbox I want to show it when they hover over the door and remove it when they hover out. This works fine, but when I hover the letter box the doors 'hover out' is fired.
This causes a strange flickering effect.
I have created a jsfiddle here showing this effect
Just wondering if anyone has a solution to this?
I basically need the letterbox to stay in place when the user hovers the door, I also need a click state for both the door and letterbox.
not sure if this is the most efficient method, but it works. jsfiddle
var doorClickState, letterbox, inletterbox = false;
$(function() {
var paper = Raphael("canvas", 330, 457);
//draw the door
doorClickState = paper.path("M0,0v200h117V0H0z").translate(0, 0).attr({
fill: "#FF0000",
stroke: 0,
opacity: 0.9
}).toFront();
//draw and hide letterbox
letterbox = paper.path("M0,0v15h60V0H0z").translate(30, 100).attr({
fill: "#000000",
stroke: 0,
opacity: 0.9
}).hide();
//click states for both
doorClickState.click(function() {
alert('door clicked');
});
letterbox.click(function() {
alert('letterbox clicked');
});
doorClickState[0].onmouseover = function() {
letterbox.show();
}
letterbox[0].onmouseover = function() {
inletterbox = true;
}
letterbox[0].onmouseout = function() {
inletterbox = false;
}
doorClickState[0].onmouseout = function() {
setTimeout(function() {
if (!inletterbox) {
letterbox.hide();
}
}, 20);
};
});