1. Code
  2. JavaScript
  3. jQuery

Persistencia simple de elementos arrastrables con jQuery

Scroll to top

Spanish (Español) translation by Luis Chiabrera (you can also view the original English article)

En algún momento, es posible que debas crear un elemento que se pueda arrastrar dentro de tu aplicación web. Esta es una gran funcionalidad, sin embargo, es posible que desees o descubras que necesita que el elemento permanezca en su lugar después de ser arrastrado. En este tutorial, te mostraré cómo arrastrar fácilmente un elemento y hacer que se pegue, incluso después de una recarga de página, tomando y almacenando sus coordenadas X e Y.

Escenario

Entonces tienes un elemento en tu aplicación web. Puedes arrastrarlo, ponerlo aquí y ponerlo allí. Pero, cuando la página se recarga de alguna manera, el elemento vuelve a su posición predeterminada. Si bien deseas que el elemento se pueda arrastrar, no deseas que se mueva después de que se haya arrastrado. Veamos una solución simple que nos brinde esta capacidad.

Empezando

Para este tutorial, necesitaremos la biblioteca jQuery, la interfaz de usuario jQuery y el complemento jQuery-JSON de Brantley Harris. También usaremos PHP y una base de datos MySQL para analizar y almacenar nuestros datos. Si eres nuevo en jQuery, no te preocupes. jQuery es una biblioteca de JavaScript altamente extensible, rápida y liviana que es divertida y fácil de usar. La biblioteca tiene documentación muy bien estructurada y una gran comunidad. Este es mi primer tutorial sobre jQuery y JavaScript, así que ten paciencia conmigo. Espero explicar todo lo mejor que pueda y si tienes alguna pregunta, no dudes en preguntar.

El HTML y CSS

Quería comenzar con el HTML y el estilo de este tutorial, ya que el efecto se aplica a los elementos HTML y ayuda a visualizar lo que vamos a hacer desde el principio. Primero el CSS:

1
html, body {
2
	background:#151515;
3
	margin:0 0 0 0;
4
	padding:0 0 0 0;
5
}
6
7
#glassbox {
8
	background:#333;
9
	border:1px solid #000;
10
	height:400px;
11
	margin:30px auto auto auto;
12
	position:relative;
13
	width:960px;
14
	-moz-border-radius: 10px;
15
	-webkit-border-radius: 10px;	
16
}
17
18
#element {
19
	background:#666;
20
	border:1px #000 solid;
21
	cursor:move;
22
	height:143px;
23
	padding:10px 10px 10px 10px;
24
	width:202px;
25
	-moz-border-radius: 10px;
26
	-webkit-border-radius: 10px;
27
}
28
29
#respond{
30
	color:#fff;
31
	margin:0 auto 0 auto;
32
	width:960px;	
33
}

El CSS es muy simple. Configuramos las propiedades html y del cuerpo para borrar los márgenes y el relleno, y continuamos estableciendo algunas alturas, anchos y otras propiedades para nuestros elementos para que no se vea tan insípido. -moz-border-radius y -webkit-border-radius son dos propiedades que nos permiten crear bordes redondeados (aplicables solo a Mozilla Firefox y Safari 3 en este momento) para nuestros elementos. Echemos un vistazo al HTML:

1
<!DOCTYPE html>
2
<html>
3
<head>
4
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
<title>Simple Draggable Element Persistence with jQuery</title>
6
7
<link rel="stylesheet" href="style.css" type="text/css" />
8
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
9
<script type="text/javascript" src="js/jquery-ui-1.7.2.custom.min.js"></script>
10
<script type="text/javascript" src="js/jquery.json-2.2.min.js"></script>
11
12
</head>
13
14
<body>
15
16
	<div id="glassbox">
17
		<div id="element"><img src="nettuts.jpg" alt="Nettuts+" />Move the Box<p></p></div>
18
	</div>
19
20
	<div id="respond"></div>

Como puedes ver, simplemente configuramos una página muy agradable y simple que llama a nuestro CSS, biblioteca de JavaScript y complementos, y contiene los elementos que usaremos para aplicar algunos efectos y eventos. Como nota, el archivo jquery-ui es una compilación personalizada que solo incluye el núcleo y la funcionalidad de interacción arrastrable.

El Javascript

¡Ahora para una jugosa interacción! Primero echemos un vistazo a algunas de las funciones básicas que usaremos para aplicar algunos efectos a nuestros elementos. Vamos a desglosarlo.

1
<script type="text/javascript">
2
	$(document).ready(function() {
3
		$("#element").draggable({ 
4
				containment: '#glassbox', 
5
				scroll: false
6
		 })

Primero le decimos al navegador: "Oye, este es un código que queremos ejecutar; no es HTML, es JavaScript". Luego queremos esperar a que se cargue el documento antes de hacer cualquier otra cosa, una vez que eso sucedió, llamamos a una función para seleccionar nuestro #element DIV, y agregamos el controlador arrastrable con algunas opciones básicas. Las opciones de contención mantendrán nuestro elemento dentro del DIV padre, y establecemos scroll en false porque no queremos que ocurra ningún desplazamiento. Sigamos adelante:

1
	.mousemove(function(){
2
		var coord = $(this).position();
3
		$("p:last").text( "left: " + coord.left + ", top: " + coord.top );
4
	})

Con este dato, llamamos al controlador de eventos mousemove y le decimos: "Cuando el mouse se mueva, establezca la variable 'coord' para que sea igual a la posición de nuestro #element seleccionado". Luego seleccionamos un párrafo ("p: last"), el último en #element, e imprimimos un texto que leerá las propiedades left(x) y top(y) de nuestro elemento en relación con el objeto padre (que es #glassbox).

1
	.mouseup(function(){ 
2
				var coords=[];
3
				var coord = $(this).position();
4
				var item={ coordTop:  coord.left, coordLeft: coord.top  };
5
			   	coords.push(item);
6
				var order = { coords: coords };
7
				$.post('updatecoords.php', 'data='+$.toJSON(order), function(response){
8
						if(response=="success")
9
							$("#respond").html('<div class="success">X and Y Coordinates Saved!</div>').hide().fadeIn(1000);
10
							setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);
11
						});	
12
				});
13
						
14
	});
15
</script>

¡Ok ahora por un poco de maldad! En este fragmento vamos a hacer un par de cosas. Primero queremos configurar una matriz vacía y luego obtener algunos valores para llenarla. Llamando al controlador de eventos .mouseup() le estamos diciendo al navegador que busque el evento cuando suelte el clic del mouse. Configuramos las variables coords para que sean iguales a nuestra matriz vacía, y nuevamente establecemos la variable coord para que sean iguales al controlador de posición de nuestro #element. Luego necesitamos crear una lista de elementos, estos serán coordTop: y coordLeft: respetuosamente igualando las posiciones izquierda y superior de nuestro #element. Con coords.push(item) literalmente estamos empujando nuestra lista de elementos y llenando la matriz de coords con ella. Luego, establece el orden de las variables como una nueva lista donde la clave de coords será igual a nuestra matriz de coords. Ahora, un poco de AJAX.

$.post es un controlador de solicitudes AJAX que carga una página remota utilizando un método HTTP POST. Esta función busca los parámetros: url, data, callback y data type to be returned. En este tutorial especificamos el archivo updatecoords.php como nuestra URL porque aquí es donde queremos enviar nuestros datos de publicación, luego definimos nuestro tipo de datos incluyendo la función $.toJSON definida en nuestro complemento jquery-JSON y configurando nuestro orden de variables como los datos que serán manejados por .toJSON. A continuación, creamos una devolución de llamada que verifica una respuesta de retorno de nuestro archivo PHP en caso de éxito, y agregamos un poco de sabor diciendo: "Si lo que se devolvió es igual al éxito, entonces ..." Mantenemos este html oculto usando el controlador de efectos .hide y dile que se desvanezca a 1000 milisegundos, espere con un tiempo de espera de 2000 milisegundos y dile que se desvanezca nuevamente. Al final, nuestro JavaScript debería verse así:

1
<script type="text/javascript">
2
	$(document).ready(function() {
3
		$("#element").draggable({ 
4
				containment: '#glassbox', 
5
				scroll: false
6
		 }).mousemove(function(){
7
				var coord = $(this).position();
8
				$("p:last").text( "left: " + coord.left + ", top: " + coord.top );
9
		 }).mouseup(function(){ 
10
				var coords=[];
11
				var coord = $(this).position();
12
				var item={ coordTop:  coord.left, coordLeft: coord.top  };
13
			   	coords.push(item);
14
				var order = { coords: coords };
15
				$.post('updatecoords.php', 'data='+$.toJSON(order), function(response){
16
						if(response=="success")
17
							$("#respond").html('<div class="success">X and Y Coordinates Saved!</div>').hide().fadeIn(1000);
18
							setTimeout(function(){ $('#respond').fadeOut(1000); }, 2000);
19
						});	
20
				});
21
						
22
		});
23
</script>

Coloca el JavaScript debajo del HTML, justo después de la etiqueta de cierre body .

El PHP

Muy bien, ahora vamos a hacer algo con los datos que se publican desde nuestro jQuery. Primero creemos una base de datos simple para almacenar nuestras coordenadas, que luego recuperaremos para definir la posición de nuestro elemento. El segundo será nuestro archivo config.php que almacenará la configuración de conexión de nuestra base de datos, y luego terminaremos con updatecords.php.

1
Database: 'xycoords'
2
3
CREATE TABLE IF NOT EXISTS `coords` (
4
  `id` int(11) NOT NULL AUTO_INCREMENT,
5
  `x_pos` int(4) NOT NULL,
6
  `y_pos` int(4) NOT NULL,
7
  PRIMARY KEY (`id`)
8
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

config.php

1
<?php
2
/*Database Settings*/
3
4
$db_host ="localhost"; //this will likely stay the same

5
$db_name = "xycoords"; //name of the database we will be using

6
$db_usr = "database_username"; //db username

7
$db_pass = "database_password"; //db password

8
9
//Connect to the database

10
$link = mysqli_connect($db_host, $db_usr, $db_pass) or die("MySQL Error: " . mysqli_error());
11
//Select our database

12
mysqli_select_db($link, $db_name) or die("MySQL Error: " . mysqli_error());
13
?>

updatecoords.php

1
<?php
2
if(!$_POST["data"]){
3
	echo "Nothing Sent";
4
	exit;
5
}
6
7
include ('config.php');
8
9
//decode JSON data received from AJAX POST request

10
$data = json_decode($_POST["data"]);
11
12
foreach($data->coords as $item) {
13
	//Extract X number for panel

14
	$coord_X = preg_replace('/[^\d\s]/', '', $item->coordTop);
15
	//Extract Y number for panel

16
	$coord_Y = preg_replace('/[^\d\s]/', '', $item->coordLeft);
17
	//escape our values - as good practice

18
	$x_coord = mysqli_real_escape_string($link, $coord_X);
19
	$y_coord = mysqli_real_escape_string($link, $coord_Y);
20
	
21
	//Setup our Query

22
	$sql = "UPDATE coords SET x_pos = '$x_coord', y_pos = '$y_coord'";
23
	
24
	//Execute our Query

25
	mysqli_query($link, $sql) or die("Error updating Coords :".mysqli_error());	
26
}
27
28
//Return Success

29
echo "success";
30
31
?>

Esto es bastante facil de seguir. Lo primero que queremos hacer es verificar que los datos de nuestra publicación se pasen al archivo. Si eso sucede, incluimos nuestro archivo de configuración para nuestra conexión de base de datos y establecemos la variable  data en json_decode(variable de publicación pasada); json_decode es una función PHP implementada en PHP 5.2.0 que nos permite decodificar una cadena JSON.

Dado que nuestra variable $data contiene una matriz de datos, debemos dividirla para obtener los valores que necesitamos. Para hacer esto, tomamos foreach $data->coords (que es de nuestra variable de orden en nuestro JavaScript) como un elemento. Esto toma cada par de clave y valor y crea un objeto de elemento a partir de la matriz, luego especificamos y creamos una variable a partir de él. Usamos esto junto con preg_replace para que podamos eliminar los caracteres que no necesitamos. Luego, como buena práctica y medida de seguridad, escapamos de nuestros valores para prepararlos para su inserción en la base de datos. Si todo va bien, debemos devolver el éxito a nuestro JavaScript para que sepa que todo salió bien.

Finalmente

Ahora que tenemos lo que necesitamos en su lugar, para tomar las coordenadas de posición de nuestro elemento y pasarlas a PHP para almacenarlas, necesitamos modificar nuestro HTML para reflejar la posición de nuestro elemento. Para hacer esto cambiamos el elemento básico HTML y en su lugar lo creamos con PHP:

1
<div id="glassbox">
2
<?php
3
		//Create a query to fetch our values from the database 	

4
		$get_coords = mysqli_query($link, "SELECT * FROM coords");
5
		//We then set variables from the * array that is fetched from the database

6
        while($row = mysqli_fetch_array($get_coords)) {
7
			$x = $row['x_pos'];
8
			$y = $row['y_pos'];
9
			//then echo our div element with CSS properties to set the left(x) and top(y) values of the element

10
			echo '<div id="element" style="left:'.$x.'px; top:'.$y.'px;"><img src="nettuts.jpg" alt="Nettuts+" />Move the Box<p></p></div>';
11
		}			
12
?>
13
</div>
14
<div id="respond"></div>

Aquí configuramos una consulta básica a la base de datos para seleccionar todas las filas de la tabla coords. Luego invocamos un ciclo while que especifica cada fila que seleccionamos como $row. Ahora podemos establecer algunas variables para que sean iguales a cada fila individual que extraemos de la base de datos y repetirlas en el lugar adecuado dentro del estilo de los elementos (izquierda y arriba).

Terminando

Bueno, espero que hayas disfrutado este tutorial tanto como yo escribiéndolo. Puede que no sea perfecto. Si bien esta es solo una forma de obtener esta funcionalidad en un elemento que se puede arrastrar, hay otras formas (y quizás mejores) de lograrlo. Una vez así, podría almacenar los valores de las coordenadas en una cookie, para mantener las llamadas a la base de datos al mínimo. También puedes serializar los valores pasados de jQuery a PHP en lugar de usar JSON. Este tutorial es solo un ejemplo del que puedes ampliar. ¡Gracias por leer!

  • Síguenos en Twitter o suscríbete a Nettuts + RSS Feed para obtener los mejores tutoriales de desarrollo web en línea.