KineticJS dragBoundFunc not working - javascript

I've got this calling function
$(document).ready(function(){
$('#change-background').click(function(){
layers['map'] = new Kinetic.Layer();
buildMap(layers['map'],'img/test.png');
stage.add(layers['map']);
});
});
And, I've got this function to display the image
function buildMap(layer, img_src){
var img = new Image();
img.src = img_src;
img.onload = function(e) {
var map = new Kinetic.Image({
id: 'map_img',
x: 0,
y: 0,
image: img,
draggable: true,
dragBoundFunc: function(pos) {
// THIS SHOULD EXECUTE
console.log('hahaha');
return { x:0, y:0 };
}
});
layer.add(map);
layer.draw();
};
}
I have a similar code on a separate project of mine, and it works like a charm.. But its quite awkward that it does not work well here. The image showed up in the canvas, and its draggable, which in this case it should not be because I explicitly returned { x:0, y:0 }(the return values is for my testing only). I also looked at the console logs the 'hahaha' text never appears.. It did not call the function when the image has been dragged. Both of these are inside a <script> tags and in one html document.

Fixed this: http://jsfiddle.net/xpLPT/2/
try :
dragBoundFunc: function(pos) {
console.log('hahaha'); //check the jsfiddle, this does work.
return {
x: this.getAbsolutePosition().x, //constrain vertically
y: this.getAbsolutePosition().y //constrain horizontally
}
}
also change your click function by adding stage.draw();:
$(document).ready(function(){
$('#change-background').click(function(){
//if(layers['map'])
// layers['map'].remove(); // this is optional, but recommended, as it removes the current map layer before adding a new one
layers['map'] = new Kinetic.Layer();
buildMap(layers['map'],'img/test.png');
stage.add(layers['map']);
stage.draw();
});
});
try using a newer version of kinetics:
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.0.min.js"></script>

Related

How to take screenshot of game div in phaser

I am using this code now, but it returns a blank transparent image:
$(document).ready(function(){
$("#t").click(function() {
html2canvas(document.querySelector("#bracelet_maker"),
{ onrendered: function(canvas){
src = canvas.toDataURL();
window.open(src); } });
});
});
If I use game.canvas.toDataUrl(); it returns a black image.
This is how the game is started in #bracelet_maker div
var game = new Phaser.Game(width,height,Phaser.AUTO,"bracelte_canvas",{
preload:preload,
create:create,
update:update });
Using Phaser.AUTO will allow either Phaser.WEBGL or Phaser.CANVAS be used, depending upon what your browser supports.
If you switch over to Phaser.CANVAS when creating your new Phaser.Game you should be able to use access the canvas.
For example, within Phaser by binding off the S key:
function create() {
// ...
var screenshotKey = game.input.keyboard.addKey(Phaser.Keyboard.S);
screenshotKey.onDown.add(function () { window.open(game.canvas.toDataURL());
}
There's also preserveDrawingBuffer which should allow you capture from WebGL as well, but it needs to be set early on in the process.
var game = new Phaser.Game(800, 600, Phaser.AUTO, '', {
preload: preload, create: create, update: update
});
game.preserveDrawingBuffer = true;

Is it possible to make a dynamic mask/crop system via fabric.js that behaves like canva.com?

edit 2016, Oct 24
I've an idea about this feature by using 'pattern' which seems to be a good idea.
I tried to prove my thoughts with this pen, its still buggy but at least we can set the image(pattern) position and keep the original image when double click.
I'am not very good at javascript, So if you are interest in this please help to make this more useable, any discussions/thoughts or code correction is welcome.
http://codepen.io/wushan/pen/LRrQEL?editors=1010
// Create Canvas
var canvas = this.__canvas = new fabric.CanvasEx('c', {
preserveObjectStacking: true
});
fabric.Object.prototype.transparentCorners = false;
// Global Settings
var url = "http://fabricjs.com/assets/pug.jpg";
//Make the Pattern by url
function createMaskedImage(url) {
//Load Image
fabric.Image.fromURL(url, function(img) {
img.scaleToWidth(300);
//Make a Pattern
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getWidth(),
height: img.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
console.log(pattern.offsetX)
console.log(pattern.offsetY)
console.log(img.getWidth()) // 縮小後 (*scale)
console.log(img.width) // 原尺寸
//Mask (can be any shape ex: Polygon, Circles....)
var rect = new fabric.Rect({
width: 200,
height: 200,
left: 150,
top: 100,
fill: pattern
})
//Bind Double Click Event from fabric.ext
//https://github.com/mazong1123/fabric.ext
rect.on('object:dblclick', function (options) {
//Pass pattern out
enterEditMode(rect, img);
});
canvas.add(rect);
canvas.setActiveObject(rect);
});
}
function enterEditMode(mask, image) {
image.left = mask.left;
image.top = mask.top;
// New Image
// Fake Crop Area (fixed)
var rect = new fabric.Rect({
width: mask.width,
height: mask.height,
left: mask.left,
top: mask.top,
fill: '#000000',
opacity: 0.8,
selectable: false
})
canvas.remove(mask);
canvas.add(image);
image.on('object:dblclick', function (options) {
//Flatten
flatten(rect, image);
});
canvas.add(rect);
// console.log(JSON.stringify(canvas));
}
function flatten(mask, image) {
//Make a Pattern
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(image);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: image.getWidth(),
height: image.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'no-repeat'
});
//Offsets
pattern.offsetX = image.left - mask.left - image.left;
pattern.offsetY = image.top - mask.top - image.top;
var rect = new fabric.Rect({
width: mask.width,
height: mask.height,
left: mask.left,
top: mask.top,
fill: pattern
})
//Bind Double Click Event from fabric.ext
//https://github.com/mazong1123/fabric.ext
rect.on('object:dblclick', function (options) {
//Pass pattern out
enterEditMode(rect, image);
});
canvas.remove(mask);
canvas.remove(image);
canvas.add(rect);
canvas.setActiveObject(rect);
canvas.renderAll();
}
//Button Events
//Create
document.getElementById('createMaskedImage').addEventListener('click', function () {
createMaskedImage(url);
});
Test this :
click 'create'
double click on the image object
move/scale the image
double click the image to flatten the obejct.
Know issue:
when cutting the image without scale, the image position looks correct but there is a wired transparent space.
It generates a lot duplicate objects on the scene...
Original Post
I've been working with fabric.js for a few month, haven't seen any example or discussions about a mask/crop system which is behaves like canva.com ( which is way easy to understand for users. )
the object looks like this:
when double clicked on a group/mask, it shows the original image with an unselectable mask, you can move/scale the image whatever you need and click 'OK' to made the change without modifying the original image.
I'd like to know if there is any possible solutions about making this in fabricjs, or maybe some thoughts about this issue is welcome.
Thank you a lot !

Using a background image with javascript pie chart

I am building an app in Rails, and I am using a gem called easy_as_pie which enables me to use this Jquery plugin called 'Easy Pie Chart' (http://rendro.github.io/easy-pie-chart/)
I have the pie chart working no problem, using the following code:
$(document).ready(function() {
$('.chart').easyPieChart({
size: 300,
animate: 1400,
lineWidth: 150,
lineCap: "butt",
scaleColor: false,
trackColor: "black",
barColor: "white"
});
});
The question I have, is whether not it would be possible to have the chart load a background image instead of a solid colour. In the documentation it allows you to use a gradient with a function, using the following code:
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
var gradient = ctx.createLinearGradient(0,0,canvas.width,0);
gradient.addColorStop(0, "#ffe57e");
gradient.addColorStop(1, "#de5900");
return gradient;
}
});
I was hoping to get the gradient working, then work on trying to manipulate the function to load in an image. But I have been unsuccessful in even getting the gradient to work.
Provided your gradient example works like it looks, you should be able to draw just about anything you want into the canvas object they've provided. With that in mind, you might be able to draw images like so:
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
var yourImage = new Image();
yourImage.src = "path-to-your-img.jpg";
return ctx.drawImage(yourImage);
}
});
However, Image objects, like <img> tags, require a further GET request to the server to actually load them, so the above probably won't actually work (sorry for the tease). Instead, you'll have to wait for that image to load before calling it, for example:
// Instantiate the image, it's blank here.
var yourImage = new Image();
// Add a callback that uses the fully-loaded img
yourImage.onload = function() {
new EasyPieChart(element, {
barColor: function(percent) {
var ctx = this.renderer.ctx();
var canvas = this.renderer.canvas();
return ctx.drawImage(yourImage);
}
});
};
// Set the src, that queues it for the actual GET request.
yourImage.src = "path-to-your-img.jpg";

Removing an image from html5 canvas when it's dragged to a certain location

I have an HTML5 canvas that is displaying a number of images and four description boxes. It is currently possible to drag and drop the images around the canvas, but I want to add functionality to remove an image when it is dragged to its correct description box.
I've tried writing the following function, but it does not currently seem to be doing anything... i.e. if I drag an image to its description box and drop it, it still remains on the canvas:
function initStage(images){
var stage = new Kinetic.Stage({
container: "container",
width: 1000,
height: 500
});
var descriptionLayer = new Kinetic.Layer();
//var imagesLayer = new Kinetic.Layer();
var allImages = [];
var currentScore = 0;
var descriptionBoxes = {
assetsDescriptionBox: {
x: 70,
y: 400
},
liabilitiesDescriptionBox: {
x: 300,
y: 400
},
incomeDescriptionBox: {
x: 530,
y: 400
},
expenditureDescriptionBox: {
x: 760,
y: 400
},
};
/*Code to detect whether image has been dragged to correct description box */
for (var key in sources){
/*Anonymous function to induce scope */
(function(){
var privateKey = key;
var imageSource = sources[key];
/*Check if image has been dragged to the correct box, and add it to that box's
array and remove from canvas if it has */
canvasImage.on("dragend", function(){
var descriptionBox = descriptionBoxes[privateKey];
if(!canvasImage.inRightPlace && isNearDescriptionBox(itemImage, descriptionBox)){
context.remove(canvasImage);
/*Will need to add a line in here to add the image to the box's array */
}
})
})();
}
}
The code I've written is based on the tutorial that I found at: http://www.html5canvastutorials.com/labs/html5-canvas-animals-on-the-beach-game-with-kineticjs/
Can anyone spot what I'm doing wrong, and how I can ensure that the image is removed from the canvas when it's dragged to its corresponding description box?
That example bugged me because it seemed old, so I edited it a little...
http://jsfiddle.net/LTq9C/1/
...keep in mind that I cant be positive that all my edits are the best way to do things, Im new and all ;)
And here I've edited it again for you to show the image being removed...
animal.on("dragend", function() {
var outline = outlines[privKey + "_black"];
if (!animal.inRightPlace && isNearOutline(animal, outline)) {
animal.remove();
animalLayer.draw();
}
});
http://jsfiddle.net/8S3Qq/1/

jQuery - running a function on a new image

I'm a jQuery novice, so the answer to this may be quite simple:
I have an image, and I would like to do several things with it.
When a user clicks on a 'Zoom' icon, I'm running the 'imagetool' plugin (http://code.google.com/p/jquery-imagetool/) to load a larger version of the image. The plugin creates a new div around the image and allows the user to pan around.
When a user clicks on an alternative image, I'm removing the old one and loading in the new one.
The problem comes when a user clicks an alternative image, and then clicks on the zoom button - the imagetool plugin creates the new div, but the image appears after it...
The code is as follows:
// Product Zoom (jQuery)
$(document).ready(function(){
$("#productZoom").click(function() {
// Set new image src
var imageSrc = $("#productZoom").attr("href");
$("#productImage").attr('src', imageSrc);
// Run the imagetool plugin on the image
$(function() {
$("#productImage").imagetool({
viewportWidth: 300,
viewportHeight: 300,
topX: 150,
topY: 150,
bottomX: 450,
bottomY: 450
});
});
return false;
});
});
// Alternative product photos (jQuery)
$(document).ready(function(){
$(".altPhoto").click(function() {
$('#productImageDiv div.viewport').remove();
$('#productImage').remove();
// Set new image src
var altImageSrc = $(this).attr("href");
$("#productZoom").attr('href', altImageSrc);
var img = new Image();
$(img).load(function () {
$(this).hide();
$('#productImageDiv').append(this);
$(this).fadeIn();
}).error(function () {
// notify the user that the image could not be loaded
}).attr({
src: altImageSrc,
id: "productImage"
});
return false;
});
});
It seems to me, that the imagetool plugin can no longer see the #productImage image once it has been replaced with a new image... So I think this has something to do with binding? As in because the new image is added to the dom after the page has loaded, the iamgetool plugin can no longer use it correctly... is this right?
If so, any ideas how to deal with it?
Wehey! I've sorted it out myself...
Turns out if I remove the containing div completely, and then rewrite it with .html, the imagetool plugin recognises it again.
Amended code for anyone who's interested:
$(document).ready(function(){
// Product Zoom (jQuery)
$("#productZoom").click(function() {
$('#productImage').remove();
$('#productImageDiv').html('<img src="" id="productImage">');
// Set new image src
var imageSrc = $("#productZoom").attr("href");
$("#productImage").attr('src', imageSrc);
// Run the imagetool plugin on the image
$(function() {
$("#productImage").imagetool({
viewportWidth: 300,
viewportHeight: 300,
topX: 150,
topY: 150,
bottomX: 450,
bottomY: 450
});
});
return false;
});
// Alternative product photos (jQuery)
$(".altPhoto").click(function() {
$('#productImageDiv div.viewport').remove();
$('#productImage').remove();
// Set new image src
var altImageSrc = $(this).attr("href");
// Set new image Zoom link (from the ID... is that messy?)
var altZoomLink = $(this).attr("id");
$("#productZoom").attr('href', altZoomLink);
var img = new Image();
$(img).load(function () {
$(this).hide();
$('#productImageDiv').append(this);
$(this).fadeIn();
}).error(function () {
// notify the user that the image could not be loaded
}).attr({
src: altImageSrc,
id: "productImage"
});
return false;
});
});
You could try abstracting the productZoom.click() function to a named function, and then re-binding it after changing to an alternate image. Something like:
// Product Zoom (jQuery)
$(document).ready(function(){
$("#productZoom").click(bindZoom);
// Alternative product photos (jQuery)
$(".altPhoto").click(function() {
$('#productImageDiv div.viewport').remove();
$('#productImage').remove();
// Set new image src
var altImageSrc = $(this).attr("href");
$("#productZoom").attr('href', altImageSrc);
var img = new Image();
$(img).load(function () {
$(this).hide();
$('#productImageDiv').append(this);
$(this).fadeIn();
}).error(function () {
// notify the user that the image could not be loaded
}).attr({
src: altImageSrc,
id: "productImage"
});
$("#productZoom").click(bindZoom);
return false;
});
});
function bindZoom() {
// Set new image src
var imageSrc = $("#productZoom").attr("href");
$("#productImage").attr('src', imageSrc);
// Run the imagetool plugin on the image
$(function() {
$("#productImage").imagetool({
viewportWidth: 300,
viewportHeight: 300,
topX: 150,
topY: 150,
bottomX: 450,
bottomY: 450
});
});
return false;
}
Also, rolled both your ready() blocks into the same block.
First, i have one question, are the .altPhoto links or images? Cause if its images then this line is wrong
var altImageSrc = $(this).attr("href");
it should be
var altImageSrc = $(this).attr("src");
its the only thing i could find in a glance

Categories

Resources