Creating custom avatars - javascript

I'm starting a project that will require that users be able to create multiple custom avatars. To do this, I want them to be able to send images that are in their inventory to a manipulation frame. Within this frame, users should be able to move and resize the images - double clicking them to remove the image from the frame and sending it back into their inventory. To the right of the manipulation frame, I would like a sortable list that will dictate the z-index of the corresponding item with the item at the top being in back of the manipulation frame. So far, I have this: http://jsfiddle.net/Thaikhan/e3Gd6/10/show/.
The list generates and is sortable but does not affect the z-index of the image. Also, the code is pretty buggy and often images will disappear off frame.
See JSFiddle here: http://jsfiddle.net/Thaikhan/e3Gd6/10/
Here is the JavaScript code:
//Click into Frame
$('.inventory').on('click', 'img', function () {
$(this).resizable({
aspectRatio: 1,
autoHide: true,
containment: "parent",
minHeight: 50,
minWidth: 50
});
$(this).parent().appendTo(".frame").draggable({
containment: "parent",
cursor: "move"
});
refreshIndexList();
});
//Double Click out of Frame
$('.frame').on('dblclick', '.ui-draggable', function () {
$(this).appendTo(".inventory");
$(this).draggable("destroy");
$("img", this).resizable("destroy").attr('style', '');
refreshIndexList();
});
//Updates List Items
function refreshIndexList() {
var listitems = $('.frame').children().length;
$('#sortable').empty();
var titles = $(".frame img:nth-of-type(1)").attr('title');
for (var count = 1; count <= listitems; count++) {
var title = $(".frame img").eq(count-1).attr('title');
var $li = $("<li class='ui-state-default'/>").text(title);
$('#sortable').append($li);
}
}
//Makes List Sortable
$(function () {
$("#sortable").sortable({
placeholder: "ui-state-highlight"
});
$("#sortable").disableSelection();
});
//Inventory Grid
$(function() {
$( "#grid" ).sortable();
$( "#grid" ).disableSelection();
});
I am a novice in JavaScript and have received much help in getting this far. I am hoping that once again I can receive help from the community and figure out how to have the sortable list change the z-index of the item. Additionally, if anyone sees why it's buggy, please let me know.
Ultimately, I want to be able to grab from the manipulation frame the image_id's, their locations, their z-indices, and their sizes and store it all in a database. This will hopefully allow users to return and edit their avatar creations.
A thousand thanks for your help!

create function with editing z-index:
function zindex() {
var title = "";
var i = 9999;
$(".ui-state-default").each(function () {
i--; //z-index position counter
title = $(this).text();
$(".frame img[title='" + title + "']").parent().css("z-index", i);
});
}
call it on adding img
$('.inventory').on('click', 'img', function () {
$(this).resizable({
aspectRatio: 1,
autoHide: true,
containment: "parent",
minHeight: 50,
minWidth: 50
});
$(this).parent().appendTo(".frame").draggable({
containment: "parent",
cursor: "move"
});
refreshIndexList();
zindex();
});
and use it on mouseup (drop event emulation)
$("#sortable").mouseup(function () {
setTimeout(function() {
zindex();}, 100);
});
FIDDLE

Related

Mouse cursor not aligned with element when appending dragged element to different div

I am experiencing an issue with the jQuery-UI draggable and droppable. The issue that I'm facing is the fact that:
When I move an element from one div to another (during dragging using
.append() ) it shifts the element away from the mouse cursor
jarringly.
I know what causes it the left / top css positions are no longer correct since I'm moving from one relative div to another. But a fix for it I can't find.
I have tried quite a few "solutions" :
Changing the cursorAt position http://api.jqueryui.com/draggable/#option-cursorAt while dragging but this only goes in affect after mouseup and on the next mousedown.
Changing the css during dragging: http://api.jqueryui.com/draggable/#event-drag which while it works is not ideal since it has hiccups that make it flicker and move in random directions which is highly annoying.
Making the draggable div absolute instead of relative (Which locally in my backbone application so far has the 'best' results but is still far from desirable since i require the elements in the sidebar to be relative so they append nicely one below the other )
Here is my JSBin example of my issue.
JavaScript
var positionStack = [];
var fieldview = $('#field');
var sidebarView = $('#sidebar');
$('.draggable').draggable({
containment: ".container",
zIndex: 100,
cursorAt: {
top: 20,
left: 25
},
snap: '.sidebar',
snapMode: 'inner'
});
$('#field').droppable({
over: function(event, ui) {
dragOverElement({event: event, ui:ui});
}
});
$('#sidebar').droppable({
over: function(event, ui) {
dragOverElement({event: event, ui:ui});
}
});
function dragOverElement(data){
var me = this;
var lastItem = positionStack[positionStack -1];
if(lastItem !== data.event.target.id)
{
positionStack.push(data.event.target.id);
var player = $(data.ui.draggable);
var target = data.event.target.id;
switch(target)
{
case ('field'):
fieldview.append(player);
player.css('position', 'absolute');
break;
case ('sidebar'):
sidebarview.append(player);
player.css('position', 'absolute');
break;
}
}
}

tooltip is shown after the 2nd hover

I have a problem, I'm trying to add a tooltip to some already rendered elements. The code that I have makes the tooltip appear after the 2nd hover which is kind of normal because on the first one is not set yet, do you know what can I do to have it displayed from the first hover?
Thanks in advance!
I have the following code:
$(".checkWidth").live("mouseenter",function() {
var size = measureText($(this).text(), 12, 'Tahoma')
var limit = $('#my_container').width() - 67;
if( size.width > limit){
$(this).attr('title', $(this).text());
$('#tiptip_content').css('font-size', '13px');
$(this).tipTip({
maxWidth: "auto",
defaultPosition: "right",
fadeIn: 100,
fadeIn: 100,
attribute: "title"
});
}
});
Calling $(this).tipTip({...}); sets up the tooltip, it doesn't show it. So you don't actually set up the tooltip until you mouseover the element, and the tooltip is shown the next time you mouse over (handled by the plugin).
You'll need to call that on DOM ready. I think you may need something like this:
$(document).ready(function () {
$('#tiptip_content').css('font-size', '13px');
var limit = $('#my_container').width() - 67;
$('.checkWidth').each(function () {
var size = measureText($(this).text(), 12, 'Tahoma');
if (size.width > limit) {
$(this).attr('title', $(this).text());
$(this).tipTip({
maxWidth: "auto",
defaultPosition: "right",
fadeIn: 100,
fadeIn: 100,
attribute: "title"
});
}
});
});
Edit another possibility:
$('#tiptip_content').css('font-size', '13px'); //this should be able to be done elsewhere...
$("document").on("mouseenter", '.checkWidth', function () {
var $this = $(this);
if ($this.data('tipInit') === true) { return; }
$this.data('tipInit', true);
var size = measureText($(this).text(), 12, 'Tahoma')
var limit = $('#my_container').width() - 67;
if (size.width > limit) {
$this.attr('title', $this.text());
$this.tipTip({
maxWidth: "auto",
defaultPosition: "right",
fadeIn: 100,
fadeIn: 100,
attribute: "title"
});
$this.trigger('mouseenter');
}
});
it depends on your code structure. But I will try the following:
Try changing the .live() to .on()
I would try to change the function to .on('hover', function)
I would also try to use mousenter and mouseleave

jQuery drag and drop with sortable

I am having an issue trying to get an array out of JS using the sortable on some drag and drop elements.
A working demo can be found at:
Example
What I need to achieve:
Drag item on image, get x,y (done)
after all items have been placed, use jQuery sortable? to get array of id's with x,y coordinates.
array(23456->{xpos:234,ypos:234},23456->{xpos:234,ypos:234},....etc
I am not sure how to bind the sortable to the items only dropped on the image, and then get those values into an array
Here is the code so far:
jQuery(function($){
$('.dragThis').bind('click', function(){
$(this).css("border","3px solid #fff");
$(this).draggable({
containment: $('body'),
drag: function(){
$('#dropHere').droppable({
accept: '.dragThis',
over : function(){
$(this).animate({'border-width' : '3px', 'border-color' : '#0f0'}, 500);
}
});
},
stop: function(){
var position = $(this).position();
var parentPos = $('#dropHere').offset();
var xPos = position.left - parentPos.left;
var yPos = position.top - parentPos.top;
var finalOffset = $(this).position();
var finalxPos = xPos;
var finalyPos = yPos;
$('#finalX').text('Final X: ' + finalxPos);
$('#finalY').text('Final Y: ' + finalyPos);
//$('.dragThis').sortable();
console.log (finalxPos,finalyPos,$(this).attr("id"));
},
revert: 'invalid'
//connectToSortable: '#dropHere'
});
});
});
Any help getting pointed in the right direction, is greatly appreciated.
Just to clarify, I will be writing the values via AJAX to a DB for recall later.
Thanks in advance
Simple solution:
Add a class for those elements on their own 'drop' event, then get all of those have classes with a selector.
After that, a handy $.fn.each() and $.fn.offset() will help.
You can then work on those coordinates with top, left instead of your mentioned xpos, ypos.
Here is an example:
var coordinates = {};
$(".dropped").each(function(item) {
coordinates[$(item).attr("id")] = $(item).offset();
});

How do I drag multiple elements at once with JavaScript or jQuery?

I want to be able to drag a group of elements with jQuery, like if I selected and dragged multiple icons on the Windows desktop.
I found the demo of threedubmedia's jQuery.event.drag:
http://threedubmedia.com/code/event/drag/demo/multi
http://threedubmedia.com/code/event/drag#demos
I think this plugin is great. Is this good and popular library? Do you know websites or applications which use it?
Are there any other libraries or plugins to drag multiple objects?
Can jQuery UI drag multiple objects?
var selectedObjs;
var draggableOptions = {
start: function(event, ui) {
//get all selected...
selectedObjs = $('div.selected').filter('[id!='+$(this).attr('id')+']');
},
drag: function(event, ui) {
var currentLoc = $(this).position();
var orig = ui.originalPosition;
var offsetLeft = currentLoc.left-orig.left;
var offsetTop = currentLoc.top-orig.top;
moveSelected(offsetLeft, offsetTop);
}
};
$(document).ready(function() {
$('#dragOne, #dragTwo').draggable(draggableOptions);
});
function moveSelected(ol, ot){
console.log(selectedObjs.length);
selectedObjs.each(function(){
$this =$(this);
var pos = $this.position();
var l = $this.context.clientLeft;
var t = $this.context.clientTop;
$this.css('left', l+ol);
$this.css('top', t+ot);
})
}
I am the author of the of the threedubmedia plugins. I added this functionality for supporting multiple elements, because I could not find a satisfactory solution anywhere else.
If you need a solution that works with the jQuery UI, here is a plugin which adds some multi-drag functionality, though the demos don't seem to work correctly in Firefox for Mac.
http://www.myphpetc.com/2009/11/jquery-ui-multiple-draggable-plugin.html
This worked for me.
Fiddle here:
var selectedObjs;
var draggableOptions = {
start: function(event, ui) {
//get all selected...
if (ui.helper.hasClass('selected')) selectedObjs = $('div.selected');
else {
selectedObjs = $(ui.helper);
$('div.selected').removeClass('selected')
}
},
drag: function(event, ui) {
var currentLoc = $(this).position();
var prevLoc = $(this).data('prevLoc');
if (!prevLoc) {
prevLoc = ui.originalPosition;
}
var offsetLeft = currentLoc.left-prevLoc.left;
var offsetTop = currentLoc.top-prevLoc.top;
moveSelected(offsetLeft, offsetTop);
selectedObjs.each(function () {
$(this).removeData('prevLoc');
});
$(this).data('prevLoc', currentLoc);
}
};
$('.drag').draggable(draggableOptions).click(function() {$(this).toggleClass('selected')});
function moveSelected(ol, ot){
console.log("moving to: " + ol + ":" + ot);
selectedObjs.each(function(){
$this =$(this);
var p = $this.position();
var l = p.left;
var t = p.top;
console.log({id: $this.attr('id'), l: l, t: t});
$this.css('left', l+ol);
$this.css('top', t+ot);
})
}
Thanks to ChrisThompson and green for the almost-perfect solution.
I wanted to add (this coming up high in google), since none of the plugins in this thread worked and it is not nativity supported by jquery ui, a simple elegant solution.
Wrap the draggable elements in a container and use an event to drag them all at once, this allows for singles draggables and multidraggables (but not really selective draggables).
jQuery(document).click(function(e) {
if(e.shiftKey) {
jQuery('#parent-container').draggable();
}
});
Check this out:
https://github.com/someshwara/MultiDraggable
Usage:$(".className").multiDraggable({ group: $(".className")});
Drags the group of elements together. Group can also be an array specifying individual elements.
Like:$("#drag1").multiDraggable({ group: [$("#drag1"),$("#drag2") ]});
Put your items into some container and make this container draggable. You will need to set handle option to be a class of your item element. Also you will need to recalculate items position after drag. And obviously when you deselect items you have to take them from this container and put back to their origin.
This is what i used, Worked in my case.
function selectable(){
$('#selectable').selectable({
stop: function() {
$('.ui-selectee', this).each(function(){
if ($('.ui-selectee').parent().is( 'div' ) ) {
$('.ui-selectee li').unwrap('<div />');
}
});
$('.ui-selected').wrapAll('<div class=\"draggable\" />');
$('.draggable').draggable({ revert : true });
}
});
};
there is Draggable in the jquery UI
all you would have to do is:
$(selector).draggable(); // and you are done!
see example here: http://jsfiddle.net/maniator/zVZFq/
If you really want multidragging you can try using some click events to hold the blocks in place
$('.drag').draggable();
$('.drag').click(function(){
console.log(this, 'clicked')
var data = $(this).data('clicked');
var all = $('.all');
if(data == undefined || data == false){
$(this).data('clicked', true);
this.style.background = 'red';
$(this).draggable('disable');
if(all.children().length <= 0){
all.draggable().css({
top: '0px',
left: '0px',
width: $(window).width(),
height: $(window).height(),
'z-index': 1
});
}
var top = parseInt(all.css('top').replace('px','')) +
parseInt($(this).css('top').replace('px',''))
var left = parseInt(all.css('left').replace('px','')) +
parseInt($(this).css('left').replace('px',''))
$(this).css({
top: top,
left: left
})
$('.all').append($(this));
}
else {
$(this).data('clicked', false);
this.style.background = 'grey';
$(this).draggable('enable');
$('body').append($(this));
if(all.children() <= 0){
all.draggable('destroy');
}
/*
var top = parseInt(all.css('top').replace('px','')) -
parseInt($(this).css('top').replace('px',''))
var left = parseInt(all.css('left').replace('px','')) -
parseInt($(this).css('left').replace('px',''))
$(this).css({
top: top,
left: left
})*/
}
})
See example here: http://jsfiddle.net/maniator/zVZFq/5

Using offset and jQuery slider

I am using offset() with the jquery slider and I am so close to achieving my goal, but it is off slighty. I have it animating using animate to the top CSS coordinates but if you check out: http://www.ryancoughlin.com/demos/interactive-slider/index.html - you will see what it is doing. My goal is to have it fadeIn() and display the value to the right of the handle. i know I can offset the text from the handle using a simple margin:0 0 0 20px.
The part is aligning #current_value to the right of the handle. Thoughts?
var slide_int = null;
$(function(){
$("h4.code").click(function () {
$("div#info").toggle("slow");
});
$('#slider').slider({
animate: true,
step: 1,
min: 1,
orientation: 'vertical',
max: 10,
start: function(event, ui){
$('#current_value').empty();
slide_int = setInterval(update_slider, 10);
},
slide: function(event, ui){
setTimeout(update_slider, 10);
},
stop: function(event, ui){
clearInterval(slide_int);
slide_int = null;
}
});
});
function update_slider(){
var offset = $('.ui-slider-handle').offset();
var value = $('#slider').slider('option', 'value');
$('#current_value').text('Value is '+value).css({top:offset.top });
$('#current_value').fadeIn();
}
I know I could use margin to offset it to match, but is there a better way?
There are two problems. The first, like Prestaul said, the slider event fires at the "beginning" of the move, not the end, so the offset is wrong. You could fix this by setting a timeout:
$(function(){
slide: function(event, ui){
setTimeout(update_slider, 10);
},
...
});
function update_slider()
{
var offset = $('.ui-slider-handle').offset();
var value = $('#slider').slider('option', 'value');
$('#current_value').text('Value is '+value).animate({top:offset.top }, 1000 )
$('#current_value').fadeIn();
}
The second problem is that the move is instantaneous, while the animation is not, meaning that the label will lag behind the slider. The best I've come up with is this:
var slide_int = null;
$(function(){
...
start: function(event, ui){
$('#current_value').empty();
// update the slider every 10ms
slide_int = setInterval(update_slider, 10);
},
stop: function(event, ui){
// remove the interval
clearInterval(slide_int);
slide_int = null;
},
...
});
function update_slider()
{
var offset = $('.ui-slider-handle').offset();
var value = $('#slider').slider('option', 'value');
$('#current_value').text('Value is '+value).css({top:offset.top });
$('#current_value').fadeIn();
}
By using css instead of animate, you keep it always next to the slider, in exchange for smooth transitions. Hope this helps!
I had the same problem: the visible value in Jquery Ui slider lags behind from internal value. Fixed the problem by changing the slider event from "slide" to "change".
You just need to use a different event. "slide" fires before the handle is moved so your value is ending up at the previous handle position. Try the "change" event and see if that gets you there.

Categories

Resources