Draggable/droppable jquery ui not working - draggable

my code is to allow sliding the same divs several times over the images, which are documents, the idea is to drag the signatures over the documents
Problems
Dragged divs are allowing to stay out of document images
Dragged divs are not being cloned, I need to drag multiple signatures
Code jsFiddle
JS Code
$(".assinaturaImagem").draggable({
containment: ".documents",
cursor: "all-scroll",
scroll: false,
//helper: "clone",
grid: [2, 2],
zIndex: 1000,
stop: function(e, ui) {
var finalxPos = ui.position.left;
var finalyPos = ui.position.top;
console.log('Stop: ' + finalxPos + ' - ' + finalyPos);
$('.assinaturaImagem').draggable().data()["ui-draggable"].cancelHelperRemoval = true;
},
helper: function (e, ui){
return $(this).clone();
}
});
$("#containerDocuments").droppable({
drop: function(e, ui) {
var xPos = ui.offset.left - $(this).offset().left;
var yPos = ui.offset.top - $(this).offset().top;
var assinaturaID = ui.draggable.attr('assinatura');
var el = ui.helper.detach();
el.css({
top: "",
left: "",
position: "absolute",
"z-index": 1000
}).appendTo(this).position({
my: "center",
at: "center",
of: e
});
}
});

Related

animating two views in titanium

I have two views displayed in a window as follows
var topView = Ti.UI.createView({
top: 0,
height: '65%',
orientation: 'vertical'
});
var botView = Ti.UI.createView({
bottom: 0,
height: '35%',
layout: 'vertical'
});
i want to animate as follows:
when a button is clicked, topView increases to hundred percent while botView decreases to 0 percent. and the reverse happens when the button is clicked.
But i haven't found a way to do it for two views.
I hope someone can help out.
Thanks -:)
EDIT:
This is what i have done so far:
var expandFlag = false;
/* create animations */
var expandAnim_map = Ti.UI.createAnimation({
height : '100%',
duration: 300
});
var expandAnim_con = Ti.UI.createAnimation({
height: '0%',
duration : 300,
bottom:0
});
var collapseAnim_map = Ti.UI.createAnimation({
height: '65%',
duration: 300,
});
var collapseAnim_con = Ti.UI.createAnimation({
height: '35%',
duration: 300,
bottom:0
});
/* create animations */
if (expandFlag) {
botView.animate(collapseAnim_con);
topView.animate(collapseAnim_map);
expandFlag = false;
} else {
topView.animate(expandAnim_map);
botView.animate(expandAnim_con);
expandFlag = true;
}
This is irregular and not beautiful, hence i'm looking for a cleaner and smoother way to do it. Thanks.
I suggest that you animate only one view in order to get a good looking animation.
You can set a higher zIndex for the top view, and then expand and reduce only that view.
var expandFlag = false;
var topView = Ti.UI.createView({
top: 0,
zIndex: 2,
height: '65%',
orientation: 'vertical'
});
var botView = Ti.UI.createView({
bottom: 0,
zIndex: 1,
height: '35%',
layout: 'vertical'
});
/* create animations */
var expandAnim_map = Ti.UI.createAnimation({
height : '100%',
duration: 300
});
var collapseAnim_map = Ti.UI.createAnimation({
height: '65%',
duration: 300,
});
/* create animations */
if (expandFlag) {+
topView.animate(collapseAnim_map);
expandFlag = false;
} else {
topView.animate(expandAnim_map);
expandFlag = true;
}

KineticJS mouse position wrong after layer rotated

My demo is here http://jsfiddle.net/akuma/7NmXw/1/
First, draw something in the blue box.
Then, click the rotate button once.
After the box has been rotated, draw something again.
Finally the draw poisitoin was wrong.
How can I fix that, thanks!
Code:
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer({
width: 400,
height: 400
});
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: 400,
height: 300,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 5
});
layer.add(rect);
stage.add(layer);
$(document).on('click', '#rotateBtn', function () {
var w = layer.getWidth(),
h = layer.getHeight();
layer.setOffset(w / 2, h / 2);
layer.setPosition(w / 2, h / 2);
layer.rotateDeg(90);
layer.draw();
});
var points = [],
drawing = false;
stage.on('mousedown', function () {
drawing = true;
var pos = stage.getMousePosition();
points.push([pos.x, pos.y]);
var line = new Kinetic.Line({
id: 'line',
points: [
[pos.x, pos.y],
[pos.x + 1, pos.y + 1]
],
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mousemove', function () {
if (!drawing) {
return;
}
// Remove previous line
layer.get('#line').remove();
var pos = stage.getMousePosition();
points.push([pos.x, pos.y]);
// Redraw line
var line = new Kinetic.Line({
id: 'line',
points: points,
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mouseup', function () {
drawing = false;
points = [];
});
Even after rotating, Kinetic will still give you un-rotated mouse coordinates
That’s because you are asking for stage.getMousePosition and the stage is not rotated.
There is no method like layer.getMousePosition, so you’ll have to create one.
If you rotate your layer 90-degrees, you must also rotate stage's mouse coordinates by 90-degrees.
Here’s how you rotate the stage mouse position to match the layer rotation:
// get the unrotated mouse position from Kinetic
var pos=stage.getMousePosition();
// rotate that point to match the layer rotation
var x1 = rotationX
+ (pos.x-rotationX)*rotationCos
+ (pos.y-rotationY)*rotationSin;
var y1 = rotationY
+ (pos.y-rotationY)*rotationCos
- (pos.x-rotationX)*rotationSin;
Since you will be doing this math with each mousemove, you should pre-calculate the rotation values to maximize performance:
// reset the current rotation information
function setRotation(degrees){
var radians=layer.getRotation();
rotationX=layer.getOffsetX();
rotationY=layer.getOffsetY();
rotationCos=Math.cos(radians);
rotationSin=Math.sin(radians);
}
Also, a bit off-topic to your question, but...
Instead of removing / recreating a new line on every mousemove, you can “recycle” your existing line:
// set the points property of the line to your updated points array
line.setPoints(points);
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/cQATv/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.5.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:400px;
height:400px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer({width:400,height:400});
stage.add(layer);
// vars to save the current rotation information
var rotationX;
var rotationY;
var rotationCos;
var rotationSin;
setRotation(0);
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: 400,
height: 300,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 5
});
layer.add(rect);
stage.add(layer);
$(document).on('click', '#rotateBtn', function () {
var w = layer.getWidth(),
h = layer.getHeight();
layer.setOffset(w / 2, h / 2);
layer.setPosition(w / 2, h / 2);
layer.rotateDeg(90);
layer.draw();
// set the info necessary to un-rotate the mouse position
setRotation(layer.getRotationDeg())
});
var points = [],
drawing = false;
stage.on('mousedown', function () {
drawing = true;
// get the rotated mouse position
pos=getPos();
points.push([pos.x, pos.y]);
var line = new Kinetic.Line({
id: 'line',
points: [
[pos.x, pos.y],
[pos.x + 1, pos.y + 1]
],
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mousemove', function () {
if (!drawing) {
return;
}
// Remove previous line
layer.get('#line').remove();
// get the rotated mouse position
var pos = getPos();
points.push([pos.x, pos.y]);
// Redraw line
var line = new Kinetic.Line({
id: 'line',
points: points,
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mouseup', function () {
drawing = false;
points = [];
});
// reset to the current rotation information
function setRotation(degrees){
var radians=layer.getRotation();
rotationX=layer.getOffsetX();
rotationY=layer.getOffsetY();
rotationCos=Math.cos(radians);
rotationSin=Math.sin(radians);
}
// rotate the stage mouse position
// to match the layer rotation
function getPos(x,y){
// normal space, no adjustment necessary
if(rotationCos==0){return;}
var pos=stage.getMousePosition();
var x1 = rotationX
+ (pos.x-rotationX)*rotationCos
+ (pos.y-rotationY)*rotationSin;
var y1 = rotationY
+ (pos.y-rotationY)*rotationCos
- (pos.x-rotationX)*rotationSin;
return({x:x1,y:y1});
}
}); // end $(function(){});
</script>
</head>
<body>
<button id="rotateBtn">rotate</button>
<div id="container"></div>
</body>
</html>

complex clipping boundary in kinetic.js with draggable image

Check out my html5 based clipping constraint on
http://shedlimited.debrucellc.com/test3/canvaskinclip.html
(messing with jsfiddle on http://jsfiddle.net/aqaP7/4/)
So, in html5 I can easily draw a shaped boundary like the following:
context.beginPath();
context.moveTo(5, 5);
context.lineTo(34, 202);
context.lineTo(2, 405);
context.lineTo(212, 385);
context.lineTo(425, 405);
context.lineTo(400, 202);
context.lineTo(415, 10);
context.lineTo(212, 25);
context.clip();
In kinetic.js though, all I see for clipping options is: height, width, and x, y,
I came across the following : Mask/Clip an Image using a Polygon in KineticJS, but the inner/fill image can't be set to draggable
any help please!
In the new kineticJS versions, a lot of the work is done in the background for you.
Take a look at this tutorial:
This fiddle gets you pretty close, here's the code:
<body>
<div id="container"></div>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.0-beta2.js"></script>
<script>
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
function draw(images) {
var stage = new Kinetic.Stage({
container: 'container',
width: 600,
height: 700
});
var layer = new Kinetic.Layer();
var patternPentagon = new Kinetic.RegularPolygon({
x: 220,
y: stage.getHeight() / 4,
sides: 5,
radius: 70,
fillPatternImage: images.yoda,
fillPatternOffset: [-220, 70],
stroke: 'black',
strokeWidth: 4,
draggable: true
});
patternPentagon.on('dragmove', function() {
//this.setFillPatternImage(images.yoda);
//this.setFillPatternOffset(-100, 70);
var userPos = stage.getUserPosition();
this.setFillPatternOffset(-userPos.x,-userPos.y);
layer.draw();
this.setX(220);
this.setY(stage.getHeight() / 4);
});
layer.add(patternPentagon);
stage.add(layer);
}
var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
};
loadImages(sources, function(images) {
draw(images);
});
</script>
</body>
There is a more complex/accurate way of doing this without making it a background pattern, like with grouping objects together

Kinetic-js: How to cache a complete layer as an image

I have a problem an hope to find any solution for it.
I am using Kinetic.js to create a HMI solution with special look-and-feel. Therefor I have created a function that creates 3 layers for a stage: a background layer with a grid, a layer with static shapes for the base layout of the HMI-screen and the third layer for all interactive elements (like buttons, valuedisplays and so on...). Now I want to cache the grid and the static layer to improve performance, because this layers will never change until the whole HMI-screen will change...
As a test I started to code the caching for the grid layer using the following code:
// Create a grid layer if showGrid is set to TRUE...
console.log('Start to create background grid if required');
if (this.actualPageConfig.showGrid) {
var grid = new Kinetic.Layer();
for (var x=1; x <= this.cols; x++) {
var eLoc = LCARSElements.posToRealPos(x, 1, this.cols, this.rows);
if (x <= this.actualPageConfig.columns) {
grid.add(new Kinetic.Line({
points: [eLoc.x, eLoc.y, eLoc.x, eLoc.height],
stroke: "red",
strokeWidth: 1,
lineCap: "round",
lineJoin: "round"
}));
}
}
for (var y=1; y <= this.rows; y++) {
var eLoc = LCARSElements.posToRealPos(1, y, this.cols, this.rows);
if (y <= this.actualPageConfig.rows) {
grid.add(new Kinetic.Line({
points: [eLoc.x, eLoc.y, eLoc.width, eLoc.y],
stroke: "red",
strokeWidth: 1,
lineCap: "round",
lineJoin: "round"
}));
}
}
// Add grid layer to stage
//this.stage.add(grid); <-- to be replaced by cache image
// Convert grid into an image and add this to the stage
console.log('convert grid to image to increase performance');
grid.toImage({
width: displayManager.stage.getWidth(),
height: displayManager.stage.getHeight(),
callback: function(img) {
var cacheGrid = new Kinetic.Image({
image: img,
x: 0,
y: 0,
width: displayManager.stage.getWidth(),
height: displayManager.stage.getHeight()
});
console.log('insert grid-image to stage');
displayManager.stage.add(cacheGrid);
console.log('redraw stage...');
displayManager.stage.draw();
}
});
}
My problem is, that's not working. The grid is not visible any more and the console log shows the following error information:
Type error: layer.canvas is undefined
layer.canvas.setSize(this.attrs.width, this.attrs.height); kinetic.js (Zeile 3167)
As I already figured out the error rise when the code "displayManger.stage.add(cacheGrid) will be executed (displayManager is the outside-class where this code snipped reside).
Can anyone see where I made the mistake? When I directly add the layer grid anything works fine...
I have created a jsfiddle to demonstrate the problem: jsfiddle
In fiddle you can run both versions by changing one parameter. Hope this helps....
Thanks for help.
Best regards
Thorsten
Actually, the problem is simpler than you might think - after caching the layer into an image, you're trying to add an image object directly to the stage (you can't do that).
To fix the problem, you need to create a new layer, say cahcedLayer, add the image to cachedLayer, and then add cachedLayer to the stage.
Check out the KineticJS info page to learn more about Node nesting:
https://github.com/ericdrowell/KineticJS/wiki
http://rvillani.com/testes/layer-to-image/
I've made this test and it worked. First, I draw 1000 squares to a layer, add this layer to a hidden stage then make an image from this stage using stage.toDataURL(). When the callback returns, I just create an Image from the data and a Kinetic.Image from the Image. Then I add it to a layer on my main (visible) stage.
Code (be sure to have a div called 'invisible'):
window.onload = function()
{
var stage = new Kinetic.Stage({
width: 520,
height: 480,
container: 'container'
});
var outerStage = new Kinetic.Stage({
width: stage.getWidth(),
height: stage.getHeight(),
container: 'invisible'
});
var layerToCache = new Kinetic.Layer();
var layer = new Kinetic.Layer();
var group = new Kinetic.Group({offset: [stage.getWidth(), stage.getHeight()]});
var anim = new Kinetic.Animation(function(frame){
group.rotate(0.02);
}, layer);
var fills = ['red', 'green', 'blue', 'orange', 'purple', 'cyan',
'black', 'brown', 'forestgreen', 'gray', 'pink'];
for (var i = 0; i < 10000; ++i)
{
(function ()
{
var size = Math.random() * 60 + 20;
var square = new Kinetic.Rect({
width: size,
height: size,
fill: fills[i % fills.length],
x: Math.random() * stage.getWidth() - 20,
y: Math.random() * stage.getHeight() - 20
});
layerToCache.add(square);
})();
}
var squaresImg = new Kinetic.Image();
outerStage.add(layerToCache);
outerStage.toDataURL({
callback: function (dataURL){
outerStage.clear();
var img = new Image();
img.src = dataURL;
img.onload = function () {
squaresImg.setImage(img);
squaresImg.setX(squaresImg.getWidth() >> 1);
squaresImg.setY(squaresImg.getHeight() >> 1);
group.setX(stage.getWidth() >> 1);
group.setY(stage.getHeight() >> 1);
group.add(squaresImg);
layer.add(group);
layer.draw();
anim.start();
}
}
});
var div = document.getElementById('invisible');
div.parentNode.removeChild(div);
stage.add(layer);
}

viewportSize seems not to work with PhantomJS

Shouldn't the output from this PhantomJS script be 240x320 pixels? I'm getting a large, default-sized image. clipRect() would seem to render the correct size image, but I need the responsive content of the page to reflect the actual browser window size.
var page = require('webpage').create();
page.viewportSize = { width: 240, height: 320 };
page.open('http://cnn.com', function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
window.setTimeout(function () {
page.render('default.png');
phantom.exit();
}, 200);
}
});
This works!!
Found the snippet on the github page of the issue.It forces the 'body' element to the page viewportSize:
var width = 1024;
var height = 768;
var webpage = require('webpage');
page = webpage.create();
page.viewportSize = {width: width, height: height};
page.open('http://harness.io', function(status) {
console.log(status);
page.evaluate(function(w, h) {
document.body.style.width = w + "px";
document.body.style.height = h + "px";
}, width, height);
page.clipRect = {top: 0, left: 0, width: width, height: height};
page.render('/tmp/test.png');
phantom.exit();
});
This is a known issue but I found a workaround:
Load the page into an iframe of whatever size you like.
Render a screenshot clipped to the rectangle of the iframe.
There is code to do it in this repository: https://github.com/jbeuckm/Splasher
This seems to work in the Mac binary for 1.9.7:
page.set('viewportSize', {width: 320, height: 480});
In CasperJS, I dealt with this issue, used the above method(s), and ultimately found it was unnecessary (at least for me, in CasperJS) once I set the single viewport options via the casper.viewport() method.
I've posted my version below, so you can see how it could work with many urls at once.
// Requires node.js and casperjs (npm install casperjs)
var casper = require('casper').create();
var root_dir = 'screenshots/';
var links = [];
var root = 'http://localhost:8001/';
var DEBUG = false;
var opts = {top: 0, left: 0, 'width': 1280, 'height': 1024};
function getHrefs() {
// Taken wholesale from casperjs
// http://docs.casperjs.org/en/latest/quickstart.html
var links = document.querySelectorAll('.days li > a');
return Array.prototype.map.call(links, function(e) {
return e.getAttribute('href');
});
}
function captureLinks(links) {
casper.echo('= SCREEN CAPTURING LINKS ====');
casper.each(links, function(self, link) {
var filename = root_dir + link.replace('/index.html', '') + '.png';
casper.echo('Capturing... ' + filename);
// Relevant code...
this.viewport(opts.width, opts.height);
self.thenOpen(root + link, function() {
// slight delay for external libraries and init loading
this.wait(500, function(){
this.capture(filename, opts);
});
});
});
}
casper.start(root, function() {
links = links.concat(this.evaluate(getHrefs));
this.echo('= GETTING LINKS ====');
if(DEBUG) this.echo(links.join('\n'));
captureLinks(links);
});
casper.run();

Resources