I've been trying to wrap my head around a very basic Javascript/jQuery task.
I've made a basic image uploader with the following HTML:
div class="button one"></div>
<div class="button two"></div>
<div class="size ui-widget-content">
<img src="" alt="" />
<input type='file' name='userFile'>
</div>
<div class="button three"></div>
This is the code I've got so far, from the jQueryUI plugin:
$( ".size" ).resizable( {
grid: [60, 24],
ghost: true,
aspectRatio: //ratio function here ,
stop: function( event , ui) {
var height = $(".size").css( "height" );
var width = $(".size").css( "width" );
$( ".size img" ).css( { width : width, height: height })
}
});
$( ".size > input" ).change(function() {
var filename = $('input[type=file]').val().replace(/C:\\fakepath\\/i, '');
var height = $(".size").css( "height" );
var width = $(".size").css( "width" );
$( ".size img" ).css( { width : width, height: height } );
$( ".size img" ).attr("src" , filename);
$( ".size img" ).attr("alt", filename );
$( ".three" ).show();
var fr = new FileReader;
fr.onload = function() { // file is loaded
var img = new Image;
img.onload = function() {
var maxWidth = 960;
var maxHeight = maxWidth * (img.height/img.width);
$( ".size, .size img" ).css( { width : img.width, height: img.height, "max-height": maxHeight , "max-width": maxWidth});
};
img.src = fr.result; // is the data URL because called with readAsDataURL
};
fr.readAsDataURL(this.files[0]); // I'm using a <input type="file"> for demonstrating
});
What I want to do is the following:
I'm trying to upload an image from my harddrive onto the page.
So far, so good.
I've used the jQueryUI Resizable function so that I can resize the image. This works perfectly.
The problem however, is that I dont know how to get the right image ratio into the Resizable function. I need this function so that my image will keep its original aspect ratio when I start resizing it.
Basically, I need to get a value from the $( ".size > input" ).change function into the aspectRatio property of the $( ".size" ).resizable function
Any ideas on how to do this?
----------------------EDIT-----------------------------------------------
I've tried #Frédéric Hamidi's solution but it doesnt work either.
I've editted the code to:
$(".size").resizable("option", "start", function( event , ui){
$(".size").resizable("option", "aspectRatio", 3 / 4);
});
But this doesnt work either. The Firebug console says:
Uncaught Error: cannot call methods on resizable prior to initialization; attempted to call method 'option'
You can set the aspectRatio property in your change handler, after the widget has been initialized, through the setter form of the widget's option() method.
$(".size > input").change(function() {
// Your current code...
$(this).parent().resizable("option", "aspectRatio", yourComputedAspectRatio);
});
Related
I've been working on a drag and drop UI with jquery UI.
I have a bunch of elements like this, that are draggable:
<i class="fa fa-laptop fa-fw"></i> Server
I can drag and clone this onto a drop zone. But when I start dragging the original element, I want to change the HTML to be
<i class="fa fa-laptop fa-5"></i>
The current code looks like this, but should I be doing something in the start event handler to clone, and change the html of the cloned element?
function MakeDraggable(ele) {
ele.draggable({
grid: [20, 20 ],
//revert: "invalid",
helper: 'move'
});
}
$(function() {
// Make the .draggable class a Draggable
//
$( ".draggable" ).draggable({
grid: [ 20, 20 ],
helper: 'clone',
appendTo: '#dropzone-panel',
start: function(event, ui) {
console.log("Dragging me.....");
}
});
// Setup the dropzone
//
$("#dropzone-panel").droppable({
drop: function(event, ui) {
console.log("Drop Event Fired");
// Get the original element id
var id = ui.draggable.attr("id");
// If this element is a copy already
// then dont clone it.
//
if (id.indexOf("-copy-") >= 0) {
console.log("This is a copy");
} else {
// This is the orginal, so clone and create a new id
var number_of_clones = document.querySelectorAll('*[id^="'+id+"-copy-" +'"]').length;
console.log("found [" +number_of_clones +"] copies");
var pos = ui.position;
var $obj = ui.draggable.clone().attr("id", id+"-copy-"+number_of_clones);
$obj.css({
position: 'absolute',
top: pos.top + "px",
left: pos.left + "px"
});
$obj.appendTo("#dropzone-panel");
// Make the clone draggable
MakeDraggable($obj);
}
}
});
Using JQuery UI draggable/droppable I am running into an issue where the draggable drop area is offset (normally to the left but inconsistent distance). The image can be directly over the drop area and fail and on next attempt, in exact same location, pass.
So, dragged item looks in correct spot over mouse but is incorrect when dropped... but only first attempt.
function dragAndDrop(draggedItem,dropZone,size)
{
var bool = 0;
var draggedItem = $(draggedItem);
var dragFromLeft = draggedItem.offset().left;
var dragFromTop = draggedItem.offset().top;
var dropZone = $(dropZone);
//var size = size;
draggedItem.draggable //Make item draggable
({
opacity:1,
revert:function()//'invalid'
{
$(".strobeRed").fadeTo(100, .50).fadeTo(100, 0);
$(this).offset({top: dragFromTop, left: dragFromLeft})
},
drag:function(event, ui)
{
$(this).height(size);
$(this).width(size);
},
cursorAt:
{
left:(size/2),
top:(size/2)
}
});
dropZone.droppable //Make item droppable
({
accept:draggedItem,
drop: function(event, ui)
{
$( ui.draggable ).fadeOut(),
$( this ).droppable( "option", "disabled", true ).css("background-color", "green"), //$(this) = $(event.target)
$( this ).draggable( "option", "disabled", true )
}
});
}
sample image
* EDIT 1
Adding function call from edge animate *
draggable and droppable objects are just divs with class names.
yepnope({nope:['jquery-ui.js','cookbook.js'],complete:init});
function init(){
dragAndDrop(".item1",'.dz1',50);
dragAndDrop(".item2",'.dz2',50);
dragAndDrop(".item3",'.dz3',50);
dragAndDrop(".item4",'.dz4',50);
dragAndDrop(".item5",'.dz5',50);
dragAndDrop(".item6",'.dz6',50);
dragAndDrop(".item7",'.dz7',50);
dragAndDrop(".item8",'.dz8',50);
dragAndDrop(".item9",'.dz9',50);
}
* EDIT 2
fixed issue, introduced another *
by having the scale prior to adding the draggable, it now drops correctly. The new issue is the first item I touch of each type scales and relocates to pointer but the drops. It doesn't fail it just stops being dragged.
function dragAndDrop(draggedItem,dropZone,scaleHeight,scaleWidth)
{
var bool = 0;
var draggedItem = $(draggedItem);
var dragFromLeft = draggedItem.offset().left;
var dragFromTop = draggedItem.offset().top;
var dropZone = $(dropZone);
var currentMousePos = { x: -1, y: -1 };
draggedItem.mousedown(function(event){
currentMousePos.x = event.pageX - (scaleWidth/2);
currentMousePos.y = event.pageY - (scaleHeight/2);
$(this).height(scaleHeight);
$(this).width(scaleWidth);
$(this).offset({top: currentMousePos.y, left: currentMousePos.x});
draggedItem.draggable //Make item draggable
({
opacity:1,
revert:function()//'invalid'
{
$(".strobeRed").fadeTo(100, .50).fadeTo(100, 0);
$(this).offset({top: dragFromTop, left: dragFromLeft})
}
})
});
dropZone.droppable //Make item droppable
({
accept:draggedItem,
drop: function(event, ui)
{
//$( ui.draggable ).fadeOut(),
$( this ).droppable( "option", "disabled", true ).css("background-color", "green"), //$(this) = $(event.target)
$( this ).draggable( "option", "disabled", true )
},
tolerance: "touch"
});
}
** I FOUND IT **
Ok, so my first attempt was calculating the draggable as its original size. The second attempt was not dragging the first item of each type during first attempt. I believe it was stuck in mousedown event and not running the draggable. every time after that draggable was already applied so it worked.
The fix was to assign draggable to everything in the beginning but pull the scaling into a second function. It now scales the item, centers it on mouse, drags and drops.
function dragAndDrop(draggedItem,dropZone,scaleHeight,scaleWidth)
{
var bool = 0;
var draggedItem = $(draggedItem);
var dragFromLeft = draggedItem.offset().left;
var dragFromTop = draggedItem.offset().top;
var dropZone = $(dropZone);
var currentMousePos = { x: 0, y: 0};
draggedItem.draggable //Make item draggable
({
opacity:1,
revert:function()//'invalid'
{
$(".strobeRed").fadeTo(100, .50).fadeTo(100, 0);
$(this).offset({top: dragFromTop, left: dragFromLeft})
}
})
draggedItem.mousedown(function(event){
currentMousePos.x = event.pageX - (scaleWidth/2);
currentMousePos.y = event.pageY - (scaleHeight/2);
$(this).height(scaleHeight);
$(this).width(scaleWidth);
$(this).offset({top: currentMousePos.y, left: currentMousePos.x});
});
dropZone.droppable //Make item droppable
({
accept:draggedItem,
drop: function(event, ui)
{
//$( ui.draggable ).fadeOut(),
$( this ).droppable( "option", "disabled", true ).css("background-color", "green"), //$(this) = $(event.target)
$( this ).draggable( "option", "disabled", true )
},
tolerance: "touch"
});
}
I'm using google maps and jquery mobile.
When the user touches a button, a map displays.
There are markers on this map, they were already known when the user touched the map display button.
This works fine. Here's the html:
<div data-role="page" style="width: 100%; height: 100%" data-ajax="false" id="map-content">
<div id="map_canvas" class="ui-content" style="width: 100%; height: 100%"></div>
</div>
Here's the javascript:
function showMap(){
var initLoc;
console.log("Pend showMap() START");
$.mobile.changePage( "#map-content", { transition: "slideup"} );
$(document).on('pageshow', '#map-content',function(e,data){
$('#map-content').height(getRealContentHeight());
initLoc = new google.maps.LatLng(0,0);
$('#map_canvas').gmap( { 'center': initLoc, 'zoom' : 16 } );
$('#map_canvas').gmap('addMarker', {'position': initLoc,
'icon': gimage,
'shadow' : shadow,
'bound': false});
for (var i = 0; i<myArr.length; i++){
var newLoc = new google.maps.LatLng(myArr[i][1], myArr[i][2]);
$('#map_canvas').gmap('addMarker', {'id':i,
'position': newLoc,
'icon': bimage,
'shadow' : shadow,
'bound': false}).click(function() {
$('#map_canvas').gmap('openInfoWindow',
{ 'content': 'some content },
this);
});
}
google.maps.event.trigger($('#map_canvas'), 'resize');
google.maps.event.trigger($('#map-content'), 'resize');
});
}
function getRealContentHeight(){
var header = $.mobile.activePage.find("div[data-role='header']:visible");
var footer = $.mobile.activePage.find("div[data-role='footer']:visible");
var content = $.mobile.activePage.find("div[data-role='content']:visible:visible");
var viewport_height = $(window).height();
var content_height = viewport_height - header.outerHeight() - footer.outerHeight();
if((content.outerHeight() - header.outerHeight() - footer.outerHeight()) <= viewport_height) {
content_height -= (content.outerHeight() - content.height());
}
return content_height;
}
The problem comes when the user leaves this page with:
$.mobile.changePage("#main", {
transition: 'slide',
reverse: true });
then adds a new marker to the map and tries to redisplay it by calling showMap()
What displays is a partial map with mostly blank space.
I've read this is a symptom of google maps not knowing the size of the screen to display, but the solution is supposed to be:
google.maps.event.trigger($('#map_canvas'), 'resize');
google.maps.event.trigger($('#map-content'), 'resize');
Can anyone suggest the proper way to add markers to a previously rendered map and then redisplay the map?
This doesn't look correct to me:
google.maps.event.trigger($('#map_canvas'), 'resize');
google.maps.event.trigger($('#map-content'), 'resize');
The first argument for google.maps.event.trigger needs to be a Google Maps Javascript API v3 object, in this case a google.maps.Map object.
The JQuery selector $('#map_canvas') does not return a google.maps.Map.
To get the required google.maps.Map, use: $('#map_canvas').gmap('getMap')
This should work for you:
google.maps.event.trigger($('#map_canvas').gmap('getMap'), 'resize');
(can't tell from your code whether there is a map on "map-content" or not, if so, you need to do the same thing there)
I have several jQueryUI sliders working with this code:
jQuery(document).ready(function ($)
{
$( '.rwmb-slider' ).each( function() {
var $this = $( this ),
$input = $this.siblings( 'input' ),
$valueLabel = $this.siblings( '.rwmb-slider-value-label' ).find( 'span' ),
value = $input.val(),
options = $this.data( 'options' );
if ( !value )
{
value = 0;
$input.val( 0 );
$valueLabel.text( '0' );
}
else
{
$valueLabel.text( value );
}
// Assign field value and callback function when slide
options.value = value;
options.slide = function( event, ui )
{
$input.val( ui.value );
$valueLabel.text( ui.value );
};
$this.slider( options );
});
});
JSFIDDLE: http://jsfiddle.net/q2BwE/
Everything works good but I'm struggling integrating in this code a function that allows me to display in a text input an average of the sliders which value is different than '0'.
Can you help me guys? Thank you
Here's one way to do it: jsFiddle example.
I added a text field (<input name="average" type="text" readonly />) to display the average that gets calculated after any of the sliders finish moving. Then I added the following code to do the calculation:
options.change = function (event, ui) {
var avg = 0;
var div = 0;
$('.rwmb-slider').each(function () {
avg += ($(this).slider('value'));
if($(this).slider('value')>0)div++
})
$('input[name=average]').val(avg/div);
};
I am using this snippet of code for my jQueryUI Autocomplete function on my site,
$( "#find" ).autocomplete({
minLength: 1,
source: function(request, response) {
var results = $.ui.autocomplete.filter(locations, request.term);
response(results.slice(0, 10));
},
focus: function( event, ui ) {
$( "#find" ).val( ui.item.value );
return false;
},
appendTo: "#results",
open: function(){
var position = $("#results").position(),
left = position.left, top = position.top;
$("#results > ul").css({left: (left + 15) + "px",
top: (top + 30) + "px", width: (206) + "px" });
},
select: function( event, ui ) {
$( "#find" ).val( ui.item.value );
$(":header.title").html(ui.item.value);
var new_url = ui.item.href; // instead of adding 'statistics', by using location.hash, it wont be necessary unlike using pushState()
location.hash = new_url;
return false;
}
})
.data( "autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "item.autocomplete", item )
.append( "<a>" + item.label + "<br />" + item.desc + "</a>" )
.appendTo( ul );
};
Actually this works perfectly fine on Firefox and Chrome, it behaves just like what it exactly behaves on the sample given here, I just merely copied and modified it according to what I wanted. But on IE9, the item.desc which shows up on other browsers is not visible on IE9. I think the code to start with fixing is the last part, the part which appends the suggestions of the autocomplete. Can someone help me out here? Cheers!
You need to upgrade bgiframe.min.js to a later version (3.0 works fine)
https://github.com/brandonaaron/bgiframe
Create a new css class to override the existing jquery ui autocomplete "position":"absolute"
.ui-autocompelte{
"position": "absolute"
....
....
}
New CSS Class
.ui-autocomplete-ie9-fix { position: relative !important; }
and apply this css class after
$("#find").autocompelte({
........
.......
});
if (!$.browser.msie || ($.browser.msie && $.browser.version != 9)) {
$("ul.ui-autocomplete").addClass("ui-autocomplete-ie9-fix");
}
Add below tag after head tag
<meta http-equiv="X-UA-Compatible" content="IE=8" />