I created a really simple map and I wanted it to be dragable.
Here is the code:
http://jsfiddle.net/AeABp/
It works, I can move the map around how I want. But I want it to be locked to the "window", so that there is never white space when it get dragged, I hope you understand what I mean.
I also had a look at the the overview from jquery-ui, but didn't find anything that I needed.
You need to constrain movement to a set of coordinates to make it work properly. Took a bit of messing with, but the containment constrains the element based on the top left corner of the element.
$(function() {
var con = $('#container');
var cw = con.width( ), ch = con.height( );
var map = $('#map');
var mw = map.width( ), mh = map.height( );
var x1 = -mw + cw, y1 = -mh + ch;
map.draggable({containment:[x1,y1,0,0]});
});
There's an easy way to do it (if i understood well):
$('#map').draggable({
containment: 'window',
scroll: false
});
Related
I have a map and an area select field:
// initialize map
var map = L.map('map').setView([38, 0], 2);
L.tileLayer('http://{s}.tile.cloudmade.com/70146506bc514228adc1756788c730d3/997/256/{z}/{x}/{y}.png', {attribution: 'Map data © OpenStreetMap contributors, Imagery © CloudMade', maxZoom: 18}).addTo(map);
var areaSelect = L.areaSelect({
width:100,
height:150,
keepAspectRatio:true
});
areaSelect.addTo(map);
areaSelect.setDimensions({width: 50, height: 50});
want to get the rectangle width and height.
var neLatCoord = $('#ne-lat-coordinate').val();
var neLonCoord = $('#ne-lon-coordinate').val();
var swLatCoord = $('#sw-lat-coordinate').val();
var swLonCoord = $('#sw-lon-coordinate').val();
var rectangle = L.rectangle([ [neLatCoord, neLonCoord], [swLatCoord, swLonCoord]]).addTo(map);
So now I want to get the rectangle width and height so I can set dimensions of the area select like this :
var rectangleWidth = rectangle.getBounds().getEast() - rectangle.getBounds().getWest();
var rectangleHeight = rectangle.getBounds().getNorth() - rectangle.getBounds().getSouth();
areaSelect.setDimensions({width: rectangleWidth, height: rectangleHeight});
but this gives another width and height? I don't know why?
Can someone help me please, cause I'm stuck on this?
Here's my JS FIDDLE
EDIT:
If I use rectangle instead of area select:
var rectangle = L.rectangle([ [21.616579, 29.487305], [7.798079, 20.522461]]);
map.addLayer(rectangle);
rectangle.editing.enable();
// Every time we move the selected rectangle, refresh data about the selected area.
rectangle.on('edit', function() {
selectedBounds = this.getBounds();
console.log("Area:", selectedBounds);
//some other code
});
$( ".select" ).click(function() {
rectangle.editing.disable();
map.removeLayer(rectangle);
rectangle = new L.rectangle([ [17.853290, 34.980469], [10.876465, 14.853516]]);
map.addLayer(rectangle);
rectangle.editing.enable();
});
When I do this reset on clicking, the event rectangle.on('edit', function() { ... is not working? I don't know why? Can you help me, please
Like the docs in leaflet-areaselect state, the method .setDimensions() needs arguments as Pixel and you give the arguments in geographical coordinates. With the leaflet map method .latLngToLayerPoint() you are able to convert geogr. coords to Pixel of your map extend.
Just change
var rectangleWidth = rectangle.getBounds().getEast() - rectangle.getBounds().getWest();
var rectangleHeight = rectangle.getBounds().getNorth() - rectangle.getBounds().getSouth();
into
var rectangleWidth = map.latLngToLayerPoint(rectangle.getBounds().getNorthEast()).x- map.latLngToLayerPoint(rectangle.getBounds().getSouthWest()).x
var rectangleHeight = map.latLngToLayerPoint(rectangle.getBounds().getNorthEast()).y- map.latLngToLayerPoint(rectangle.getBounds().getSouthWest()).y
Here is the working JS FIDDLE
I know this thread is about a year old, but I figured someone else might benefit from my trouble with the provided answer.
Leaflet actually provides 2 conversion methods:
latLngToLayerPoint()
latLngToContainerPoint()
The difference between the two has to do with how x,y positions are calculated.
LayerPoint finds x,y positions relative the top-left corner of the map when it is initialized!!! (Zooming resets this origin point, but panning does not!)
ContainerPoint finds x,y positions relative to the top-left corner of the map container itself.
Why does that matter?
If you initialize your map, pan it, and then get x,y coords using latLngToLayerPoint(), you can potentially get negative x/y values, which can lead to negative widths/heights if you don't actively compensate for them.
At least in my use-case, it was better to use latLngToContainerPoint() when determining boundary heights/widths in pixels.
Other than that, the above answer worked perfectly for me! :D
So Im trying to make something where the user is able to drag planets along their orbits and it will continuously update the other planets. Ideally I would like this to work with ellipses too.
So far I can drag an image node with jquery and check/change the coordinates, but i cannot update the position reliably while the user is dragging the object. I know there is an axis and a rectangle containment for draggable but this doesn't really help me.
I have a site for calculating planetary orbits http://www.stjarnhimlen.se/comp/ppcomp.html and a formula i think should help me if i can figure out how to constrain the draggable object with coordinate checks Calculating point on a circle's circumference from angle in C#?
But it seems like there should be an easier way to have a user drag a sphere along a circular track while it updates coords for other spheres
here's what i have so far. It's not much
http://jsfiddle.net/b3247uc2/2/
Html
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
Js
var $newPosX = 100,
$newPosY = 100;
//create image node
var x = document.createElement("IMG");
x.src = "http://upload.wikimedia.org/wikipedia/commons/a/a4/Sol_de_Mayo_Bandera_Argentina.png";
x.width = 100;
x.height = 100;
x.id = "sun";
x.hspace = 100;
x.vspace = 100;
document.body.appendChild(x);
//coords
var text = document.createTextNode($newPosX + " " + $newPosY);
document.body.appendChild(text);
//make sun draggable and update coords
$("#sun").draggable({
drag: function (event, ui) {
$newPosX = $(this).offset().left;
$newPosY = $(this).offset().top;
}
});
//0 millisecond update for displayed coords
setInterval(check, 0);
function check() {
//tries to constrain movement, doesn't work well
/*
if ($newPosX > 300) {
$("#sun").offset({
left: 200
});
}
*/
text.nodeValue = ($newPosX + " " + $newPosY);
}
Edit:
I found this and am trying to modify it to suit my purposes but have so far not had luck.
http://jsfiddle.net/7Asn6/
Ok so i got it to drag
http://jsfiddle.net/7Asn6/103/
This is pretty close to what I want but can be moved without being clicked on directly
http://jsfiddle.net/7Asn6/104/
Ok final edit on this question. This one seems to work well and have fixed my problems. I would still very much like to hear peoples implementation ideas or ideas to make it work smoother.
http://jsfiddle.net/7Asn6/106/
Logo and elements from ul once clicked rotates image. By default image is already rotated by certain degrees, then on each click image rotates to necessary value.
So far I was using the following:
$("#objRotates").css('opacity','.2');
var value = 0;
var prev_value = 0;
$( "li" ).click(function() {
var text=$(this).text();
if(text==="text1"){value=0;}
if(text==="text2"){value=33;}
if(text==="text3"){value=66;}
if(prev_value != value){
$("#objRotates").animate({opacity:'1'});
$("#objRotates").rotate({
animateTo:value,
easing: $.easing.easeInOutExpo,
center: ["25px", "150px"],
callback: function(){$("#objRotates").animate({opacity:'0.2'});}
});
}
prev_value = value;
});
Above code is the one that was used before, where images start position was 0 and its animation was triggered from link text.
Using jqueryRotate.js examples(here)
How do I change the code, so that images start position is certain degrees and animation starts if element with specific ID is clicked?
Give at least clue..Cause for now, looking at my old code, I am lost. Thanks in advance.
SIMPLIFIED FIDDLE
Ok, so I've created a couple of samples for you to check out. The first one is very basic and I've simplified the code a little to make it easier to understand. This one just uses completely static values and a static elementId for the event, which I'm pretty sure answers your question based on your response to my comment yesterday. http://jsfiddle.net/x9ja7/594/
$("#elementId").click(function () {
var startingAngle = 45;
var endingAngle = 90;
var elementToRotate = "img";
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
});
});
But I wanted to give another example as well that would be dynamic and repeatable for multiple elements. With the code above, you would have to copy/paste the same code over and over again if you want to perform this animation by clicking different elements. Here's an alternative. In this example, you set all of your parameters in the data attributes in the clickable element, then the function is completely repeatable, you only have to write it once. Less code = everyone happy! Here's the example: http://jsfiddle.net/x9ja7/595/
//#region Default starting angles
$("#image1").rotate({ angle: 90 });
$("#image2").rotate({ angle: 20 });
//#endregion
$(".rotateAction").click(function () {
//#region Optional parameter - used in the optional callback function
var $self = $(this);
//#endregion
var startingAngle = Number($(this).attr("data-startingangle"));
var endingAngle = Number($(this).attr("data-endingangle"));
var elementToRotate = $(this).attr("data-elementtorotate");
//#region If the current angle is the ending angle, reverse the animation - this can be removed if you want, I thought it may be cool to show some of the things you can do with this.
var currentAngle = $(elementToRotate).getRotateAngle();
if ( currentAngle[0] === endingAngle) {
startingAngle = Number($(this).attr("data-endingangle"));
endingAngle = Number($(this).attr("data-startingangle"));
}
//#endregion
$(elementToRotate).rotate({
angle: startingAngle,
animateTo: endingAngle
//#region This is optional - uncommenting this code would make the animation single-use only
//, callback: function () { $self.off().removeClass("clickable"); }
//#endregion
});
});
Hope this helps. If you need any other assistance, please let me know.
I would like to draw(animate a line) in Raphael to the edge of the screen/browser from e.g. the x=100, y=100 pixels to the very right edge of the screen.
I know how to do the animation part, I just need to know how can I dynamically find out the rightest coordinates.
How to do such thing without creating a horizontal scroller in browser?
Is this possible in Raphael js or not at all?
My code so far:
var paper = Raphael(100, 100, ???, 1);
var lineToEdge = paper.path("M0 0");
lineToEdge.attr(fillerLine);
var anim = Raphael.animation({path: "M0 0L??? 100"}, 500);
lineToEdge.animate(anim.delay(2500));
??? - variables that will somehow give me the rightest x position.
Use Javascript's window.screen object to get this info.
See: http://www.javascriptkit.com/howto/newtech3.shtml
So your code would look like (sorry, haven't tested this myself):
var paper = Raphael(100, 100, screen.width, 1);
var lineToEdge = paper.path("M0 0");
lineToEdge.attr(fillerLine);
var anim = Raphael.animation({path: "M0 0L"+screen.width+" 100"}, 500);
lineToEdge.animate(anim.delay(2500));
At onclick event I am adding marker (image pin.png):
var relativeX = event.pageX;
var relativeY = event.pageY;
R.image("pin.png", relativeX, relativeY, 22, 22);
R in this code is Raphael paper: var R = Raphael("paper", 500, 500);
And I have to add also textbox next to this pin. It will be something like description of this marker. There should also be delete icon next to it that would remove both marker and textbox. User can add unlimited number of markers.
How can I add this textbox and icon/button to remove both marker and it's textbox?
I am using JQuery and Raphael.
Raphael's ability to handle text is absolutely horrible. I recently had to do something simular for a project, and i ended up using an HTML5 canvas to generate an image, and then load that image into my project.
So say you create your rect in Raphael, then you'll want to generate an image with your description in it:
var width = myRect.getBBox().width
var height = myRect.getBBox().height
var canvas = jQuery("<canvas width="+width+"px height="+height+"px />");
var context = canvas[0].getContext("2d");
context.font = "10pt Calibri ";
context.textAlign = "left";
context.textBaseline = "top";
context.fillText("this is text", xPos, yPos);
and then you'll want to move it into raphael:
var img = canvas[0].toDataURL("image/png"); //turns the canvas object into a png and returns the dynamic url
var bb = myRect.getBBox();
paper.image(img,bb.x,bb.y,300,400)
Its not the 'easiest solution in the world.. but i think you'll find that other options are not very fun to deal with.
Other options include
var description = paper.text(0,0,"this is text");
which may work better for you, but if you're doing any thing with zooming in and out, or even possibly dragging objects, you will have a hard time.
as for your adding markers bit, you'll probably want a function that says something like
function addMarker(x,y){
var marker = paper.set();
marker.push(
paper.rect(x,y,5,20).attr({fill:"#000"}),
paper.rect(x,y,10,5).attr({fill:"#000"}),
);
}
and you'll want a click function as well, something like
$("paper").click(function(e){
addMarker(e.offsetX,e.offsetY)
});
I hope this helps some. Feel free to comment if you need any more help.
edit:
To remove raphael elements, you can use
myElement.remove();
or even
myElement.hide();
edit:
I thought you might have been looking for an input field... Which is something that Raphael can't handle. So you're going to have to do some work arounds.
If you create an input field and then position it absolutely on top of your raphael program you can achieve this.
var textbox = $("<textarea/>");
textbox.css({"z-index" : 2, "position" : "absolute"});
textbox.css("left",myRaphaelElement.getBBox().x)
textbox.css("top",myRaphaelElement.getBBox().y)
$("body").append(textbox)
and i imagine you're going to want the user to be able to save what they write.. which is where you'll add a butotn and do something like
button.onclick(function(){
// write code here that involves the bit i wrote earlier in my post
// that takes textbox.val() as your text.
});
better?
I ended using simple javascript:
var relativeX = event.pageX;
var relativeY = event.pageY;
$('.marker').append('<div class="pin_container" style="top:' + relativeY + 'px; left:' + relativeX + 'px;"> <input type="text" name="textbox" id="textbox' + counter + '" value="" class="pin_textbox"><input type="button" id="remove" class="delete_button" value=" "></div>');
counter++;
$(".delete_button").click(function () {
$(this).parent().remove();
});
Operations on text in Raphael are way to much complicated.