tech explorers, welcome!

Autor: TRW (Página 3 de 4)

😃 Usa un Emoji como favicon para tus web-apps

Visto en: https://css-tricks.com/emoji-as-a-favicon/

Toda web necesita su favicon: ese iconito que sale junto al título de la página.

Normalmente, tu favicon sería una pequeña imagen que enlazas en el encabezado del .html, como en este blog (aunque aquí lo hace WordPress por mí).

<link rel="icon" href="https://theroamingworkshop.cloud/b/wp-content/uploads/2022/08/cropped-TRW-favicon-1-32x32.png" sizes="32x32">

Pero para tus webapps de uso personal no es necesario perder el tiempo diseñando una imagen, ni tampoco dejar el cutre icono por defecto del navegador.

Puedes usar un Emoji, que le dará un toque más personal a tu página, tal y como nos indica Lea Verou en este tweet:

Resumiendo

Vamos, que todo lo que tienes que hacer es copiar y pegar lo siguiente:

  1. Pega este código dentro de tu <html>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>">
  1. Sustituye el icono «⚡» por cualquiera de los símbolos HTML, como los que encontrarás en w3schools (selecciónalo y cópialo):

https://www.w3schools.com/charsets/ref_emoji.asp

  1. En caso de que veas símbolos raros en lugar del icono, añade codificación UTF-8 a tu documento:
    <meta charset="UTF-8">

Código ejemplo

Aquí te dejo un código de ejemplo para que lo pruebes en un archivo .html en tu ordenador.

<html>

<meta charset="UTF-8">

<title>Mi web app</title>

<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>">

</html>

Consulta y comparte este y más trucos de diseño web en 🐦 Twitter!

🐦 @RoamingWorkshop

Procesar imágenes satélite de Landsat o Sentinel 2 en QGIS

Si conoces mis artículos de #WarTraces, verás que utilizo imágenes satélite de la Agencia Espacial Europea. Hoy os cuento cómo descargar y manipular estas imágenes de la misión Sentinel 2, así como de Landsat, ya que el tratamiento es similar para ambos.

Lo haremos con QGIS, para lo cual deberás descargar e instalar este programa con el módulo de GRASS GIS incluido.

Registro en plataformas.

Necesitaremos crearnos una cuenta para poder acceder a ambas fuentes de datos, rellenando un formulario y confirmando la cuenta por correo electrónico.

Copernicus Open Access Hub

https://scihub.copernicus.eu/dhus/#/self-registration

NASA Earthdata Search

https://urs.earthdata.nasa.gov/users/new

Descarga de datos.

Diferenciemos según la plataforma utilizada.

Copernicus Open Access Hub

Accedemos a su visor de datos y nos logueamos con las credenciales creadas.

https://scihub.copernicus.eu/dhus/

Ahora, dibujaremos el polígono delimitador de la zona de interés. Cada punto del rectángulo se marca haciendo click derecho, y cerramos el polígono con doble click derecho.

A continuación, pulsamos el botón de filtro de la barra de búsqueda y seleccionamos la casilla de la misión Sentinel-2 (también podremos delimitar las fechas de la consulta, pero por defecto se ordenará de más reciente a más antiguo).

Por último, aparecerán los productos disponibles para nuestra consulta, los cuales podremos previsualizar o descargar en un fichero .zip comprimido.

NASA Earthdata Search

Igual que antes, deberemos loguearnos primero en su visor de datos.

https://search.earthdata.nasa.gov/search

Podremos definir también una zona de interés mediante las herramientas de geometría de la barra lateral.

Filtramos los productos, por ejemplo seleccionando "Imagery", y seleccionamos HLS Landsat en el catálogo.

En este caso, deberemos seleccionar las bandas que queramos descargar y que veremos a continuación.

Imagen TCI (true colour o color verdadero)

Simplificando (mucho), los satélites capturan imágenes en distintos rangos de longitudes de onda, denominados bandas.

Además, las imágenes o fotografías digitales que usamos para representar la realidad como las ve el ojo humano suelen estar definidas por tres capas de datos: una para el color rojo (Red), otra para el color verde (Green), y otra para el azul (Blue), definiendo en cada una de estas capas un valor para cada pixel con la cantidad de ese color. La combinación de todos los píxeles es lo que simula una imagen similar a la realidad.

TIP! Haz la prueba y haz mucho zoom a cualquier imagen y verás el mosaico de píxeles que la forma.

Utilizaremos las bandas capturadas por los satélites dentro de la longitud de onda visible para generar una imagen tal y como la veríamos desde el espacio.

Sentinel 2

En el caso de Sentinel 2, podemos mostrar directamente una imagen de color verdadero descargando el producto L1C y empleando la capa _TCI.jp2 ubicada en la ruta /GRANULE/DATA_CODE_NAME/IMG_DATA/

La imagen TCI se verá de la siguiente forma:

Deir ez Zor, Siria, 22/10/2017. TCI. Fuente: Copernicus Sentinel 2.

Landsat

TIP! https://gisgeography.com/landsat-8-bands-combinations/

Para Landsat, deberemos combinar las diferentes bandas capturadas individualmente por el satélite dentro de la longitud de onda visible. Estas son:

REDB04
GREENB03
BLUEB02

Acudimos a QGIS, y usamos la función i.group del módulo GRASS que combinará las capas seleccionadas en una nueva capa multibanda RGB.

Para facilitar la tarea, yo renombro las capas para ordenarlas de la siguiente manera, asegurándote que el script las lee correctamente:

Quedando así:

En este caso no se parece nada a la imagen anterior o a la realidad, así que ajustamos las propiedades para extraer más color de los datos:

  • En primer lugar nos aseguramos de leer toda la información de las bandas usando los valores mínimo y máximo reales, en lugar de los estimados.
  • Solo con esto mejora bastante la imagen, pero le falta algo de brillo y de color.
  • Ajustamos ahora los parámetros de renderizado de color:

Y ya queda algo mucho más realista:

Deir ez Zor, Siria, 21/10/2017. TCI. Fuente: Landsat.

Capa SWIR (short wave infra-red)

Utilizando las bandas de longitud de onda infra-roja, podemos ver más allá de lo que ve el ojo humano, o incluso a través de ciertos objetos, como es el caso de ciertas nubes o el humo.

Durante los incendios del verano, vi cómo Copernicus utilizaba estas imágenes para delimitar la extensión del fuego, y pensé que servirían para localizar el impacto de las bombas que oculta el humo que desprenden. Y así fue cómo se me ocurrió utilizarlo para #WarTraces.

Sentinel 2

Usamos el procedimiento anterior, combinando para este caso las siguientes bandas:

REDB12
GREENB8A
BLUEB04
Deir ez Zor, Siria, 22/10/2017. SWIR. Fuente: Copernicus Sentinel 2.

Landsat

Realizamos una nueva combinación, en este caso usando las bandas siguientes:

REDB07
GREENB06
BLUEB04
Deir ez Zor, Siria, 21/10/2017. SWIR. Fuente: Landsat.

Conclusión

Como nota final, es importante destacar el tamaño de pixel, ya que afectará al detalle de la imagen (resolución):

  • Sentinel 2: 10 metros.
  • Landsat: 30 metros.

Por otro lado, Landsat cuenta con imágenes desde 2013, mientras que Sentinel solo dispone de imágenes desde 2015.

Además, puedes previsualizar todas estas capas y combinaciones con visores web como EO Browser de Sentinel Hub.

Bombardeos al Aeropuerto Internacional Antonov en Kyiv, Ucrania, el 26/2/2022, usando EO Browser.

Si te atascas o quieres comentar, te espero en 🐦 Twitter!

🐦 @RoamingWorkshop

BlenderGIS: modelado 3D de información geográfica en Blender

Blender es (para mí), el programa de modelado 3D gratuito por excelencia. Tiene una amplísima comunidad, muchísima documentación, tutoriales y, sobre todo, continuas actualizaciones y mejoras.

Uno de sus plugins más útiles es BlenderGIS, con el que podremos volcar datos geográficos, georreferenciados o no, para poder modelar con ellos.

Vamos a ver un ejemplo de uso para un modelo de elevaciones.

Instalación

Lo primero que debemos hacer es descargar e instalar Blender desde su fuente oficial (su página web) o desde la tienda de aplicaciones de nuestro sistema operativo:

https://www.blender.org/download/

Ahora descargaremos BlenderGIS desde el github de su autor en su formato .zip comprimido:

https://github.com/domlysz/BlenderGIS

A continuación ejecutamos Blender y abrimos los ajustes de Add-ons (Edit > Preferences > Add-ons).

Pulsamos en "Install..." y seleccionamos el fichero .zip de BlenderGIS.

Ahora podremos buscarlo y activarlo.

Verás que ahora aparece el menú "GIS" en la barra superior de Blender.

Descargar información geográfica

En este ejemplo yo voy a usar un Modelo Digital del Terreno en formato ASCII (.asc), ya que es uno de los formatos de trabajo de BlenderGIS y también el formato estándar de descarga.

Si la información la descargas en otro formato como .tiff o .xyz, lo podrás convertir usando algún programa de escritorio como QGIS o ArcGIS.

MDT

En mi caso, usaré el MDT200 del IGN español, un modelo con paso de malla (o tamaño de celdas) de 200 metros, y es que quiero representar una zona bastante amplia que incluye la provincia de Álava.

https://centrodedescargas.cnig.es/CentroDescargas/index.jsp

Ortofoto

Además, podemos usar una ortofoto como textura del terreno. Para ello me ayudaré de QGIS, y cargaré el servicio WMS del PNOA (también del IGN) para recortar la imagen satélite al gusto.

Cargada la ortofoto, la exportaremos como imagen renderizada para la extensión de nuestro MDT, y con tamaño de celda de 20 metros (la ortofoto admite hasta unos 20cm de tamaño de celda, pero el archivo sería ya excesivamente grande, siendo la imagen de 20 metros de 140MB).

TIP! Una forma de optimizar el detalle es generar "teselas", o una cuadrícula de menor tamaño, pero mayor resolución.

Modelado en Blender

Así estaría todo listo para trabajar en Blender.

Usando el menú "GIS", importamos la capa como malla ASCII. Verás que en seguida aparecerá el modelo en pantalla.

TIP! Este modelo está centrado en el origen de coordenadas, pero se podría georeferenciar estableciendo su CRS en las propiedades de "Georeference".

Ahora añadimos la textura satélite:

  1. Creamos un nuevo material.
  1. Creamos una nueva textura y cargamos la imagen satélite.
  1. Ahora nos movemos a la pestaña de UV Editing:
    • Selecciona la capa de terreno en la ventana derecha, entra en Edit Mode, y "Seleccionar todos" los polígonos (Ctrl+A). Deberías verlo naranja como abajo y asegúrate de estar en la vista "Supertior" (pulsa el número 7).
    • Despliega las herramientas "UV" del menú superior y proyecta la capa del terreno con "Project from View (bounds)". Esto hará que se ajuste a la extensión de la imagen.
  1. Elegimos la imagen de la textura para aplicarle la proyección y vemos que se ajustan las celdas del modelo a la imagen (haz un poco de zoom para comprobarlo).
  1. Por último, vamos a la pestaña de Shading y añadimos el elemento "Image Texture" seleccionando la imagen de la textura y conectamos el Vector al UV y el Color al Shader (copiar la imagen).

Ahora, si volvemos a la ventana de Layout, nuestro modelo mostrará la imagen satélite perfectamente ajustada.

Y ya estaría listo, con esto puedes ahora editar y exportar tu modelo, por ejemplo, para imprimirlo en 3D o usarlo en Unity3D.

¿Dudas o comentarios? Pásate por 🐦 Twitter!

🐦 @RoamingWorkshop

Comprueba el rastreo que hacen las webs que visitas.

Si quieres comprobar el seguimiento que hace de tí una web haz este sencillo experimento.

  1. Entra en el inspector del navegador con Crtl+I o click derecho «Inspeccionar»
  2. Abre la pestaña de «Red».
  3. Ahora ve a la página principal del blog.

Esto es lo que verás: apenas 8 archivos que cargan todo lo necesario para que navegues por el blog.

Ahora abre cualquier otra página que suelas visitar y observa la misma pestaña de red.

Yo voy a entrar en amazon.es y no voy a entrar en detalles. Solo fíjate que se irá generando un nuevo fichero /1/batch/1/OE al final cada poco tiempo. Ahora mueve despacio el ratón sin bajar la ventana. Verás que el contenido de esos ficheros contiene una variable t de tiempo y unas coordenadas x e y que indican donde tienes el cursor en cada momento. Esto es solo un ejemplo del tracking que se realiza habitualmente: desde dónde entraste a la web, qué clickas, qué ves, donde te detienes, tu IP, tu geolocalización… Aquí no hay nada de eso.

Esto en cuanto a Amazon y su AWS. Los ficheros de rastreo de Google son los famosos «analytics» o «collects» que también verás en la pestaña de Red en las páginas que lo utilicen (que son la mayoría).

Se suele decir que la mejor solución es la más sencilla, y de hecho, como ves en este blog, no necesitas tantas florituras para publicar una web. Así que desconfía de sitios tediosos, con un interminable listado de «partners» y con servicios de Google Analytics o Amazon Web Services.

Cuida tu navegación!

AnalogTouch: sensor táctil con cualquier pin analógico en Arduino

Una de las formas de evitar el uso de botones aparatosos en tus proyectos Arduino es utilizar placas o módulos con pines táctiles, como algunos módulos de ESP32.

Eso sí, la mayoría de placas no cuentan con esta característica, pero leyendo esta entrada en el foro de esp32.com di con algo interesante:

https://www.esp32.com/viewtopic.php?t=23066

Con una rápida calibración, se puede usar cualquier pin analógico como sensor táctil. Aunque hay varias librerías al respecto, realmente solo necesitas un par de funciones, así que vamos al grano!

Componentes

Para este proyecto voy a usar los siguientes compontentes:

Cableado

Si usamos la Pro Micro, esta es la asignación de pines:

Pro MicroComponente
Puerto Micro USBCable USB
Pin 21 (A3)Cable puente desconectado
Pin 20LED+
GNDResistencia

Solo debemos tener en cuenta que el cable puente que usaremos como sensor táctil deberá ir conectado a un pin analógico.

(la placa mostrada no corresponde exactamente con la Pro Micro)

Sketch de Arduino

En mi github puedes encontrar un sketch de Arduino listo para usar:

https://github.com/TheRoam/TRW_AnalogTouch/blob/main/ProMicro_Blink_AnalogTouch.ino

Verás que indica "ProMicro", pero realmente es compatible con cualquier microcontrolador. Solo tienes que elegir tu placa en el menú de Herramientas.

La Pro Micro lleva un controlador ATMega32u4, que es compatible con la placa Arduino Leonardo.

Con esta configuración, compilamos el script y lo subimos a la placa.

Resultado

Abrimos el Monitor Serie, que debería aparecer en blanco ya que el texto de depuración está configurado al mínimo por defecto.

Ahora tocamos el extremo libre del cable puente y veremos cómo se ilumina el led, y cómo se detecta el "toque" en el Monitor Serie.

También verás que el script acumula los "toques" para poder utilizarlos en otros programas.

Al código

Brevemente explico lo que hace el programa:

  1. Durante el setup(), iniciamos la comunicación por serie, activamos el pin para el led, y rellenamos la matriz de lecturas analógicas con unas lecturas iniciales con setTouch (Por defecto se leen 20 valores).
void setup() {
  // initialize serial communication at 115200 bits per second:
  Serial.begin(115200);
  //enable LED pin
  pinMode(LP,OUTPUT);
  setTouch(TP);
}
  1. A continuación, pasamos a la función de ejecución continua loop() donde refrescaremos las lecturas al inicio de cada bucle.
setTouch(TP);
//------loop continues------//
void setTouch(int tp){
  //fill up the array
  for(int a=0;a<VALUES;a++){
    mean[a]=analogRead(tp);
    delay(10);
  }
}
  1. Comprobamos si la depuración es mínima o extendida y ejecutamos el programa principal correspondiente (es el mismo, pero con mayor salida al Monitor Serie).
//run check
  if(out==1){
    extended(TP);
  }else if(out==0){
    minimal(TP);
  }
  1. El programa principal:
    1. Recorre la matriz de lecturas,
    2. Obtiene la media de los valores,
    3. Obtiene una nueva lectura,
    4. Calcula la diferencia de tensión entre la última lectura y la media,
    5. Si el valor es mayor que la caida de tensión de referencia, se identifica "toque", se imprime por Monitor Serie, se suma al contador y se ilumina el led.
    6. Se restaura la media a 0, se apaga el led y se devuelve la variable de "toques".
int minimal(int tp){
  //start reading values
  for(int i=0;i<VALUES;i++){
    //get average of array
    for(int j=0;j<VALUES;j++){
      avg+=mean[j];
    }
    
    avg=avg/VALUES;

    //read current value
    fin=analogRead(tp);
    
    //compare average with current value
    if((avg-fin)>REFV){
      Serial.println("----------  T   O    U    C    H  ----------");
      //increase counter
      touch++;
      //print touch count
      Serial.print("T: ");
      Serial.println(touch);
      //light led
      ledON(LP);
      //wait 1 second after touch detected
      delay(1000);
    }
    //restart counter
    avg=0;
    //restart led
    ledOFF(LP);
    delay(VALINTERVAL);
  }
  return touch;
}
  1. Con esto se reinicia el bucle, volviendo al punto 2.

Otras configuraciones

El script cuenta con diversas variables de configuración que encontraremos en los '#define's

  • OUT: define la cantidad de texto de depuración. Valor 0: mínimo; Valor 1: extendido.
  • VALUES: tamaño de la matriz de valores analógicos.
  • TOUCHPIN: definir el número del pin analógico a usar.
  • LEDPIN: definir el número de pin usado por el led.
  • VALINTERVAL: intervalo de evaluación en milisegundos.
  • REFV: valor de caida de voltaje (en milivoltios) que identifica un "toque".
// OUTPUT verbosity
// 1: extended --> Prints ADC array, mean value, touch count and touch message with touch count
// 0: minimal  --> Prints touch message with touch count

#define OUT 0

// comparison variables
#define VALUES 20       //values for mean array
#define TOUCHPIN 3      //touch pin
#define LEDPIN 20       //led pin
#define VALINTERVAL 100 //evaluation interval
#define REFV 80         //reference voltage drop in mV

Calibración

Cambiando la configuración se puede calibrar el script para distintas placas. Con lo que he probado, esta es una buena secuencia:

  1. Define una REFV alta, por ejemplo 1000
  2. Carga el script con depuración extendida (OUT 1)
  3. Abre el Monitor Serie y observa los valores medios (Average: 230)
  4. Ahora, toca el cable puente y observa de nuevo los valores medios (Average: 170)
  5. Haz la resta entre las medias en 3. y en 4. (230-170=60).
  6. Define el REFV con este valor y calibra a partir de aquí.
    • Para más sensibilidad, defínelo más bajo (50).
    • Si es excesivo puede detectarse sin contacto. Auméntalo (80).
    • Debido a la carga del CPU, REFV puede variar si hay depuración OUT 1 respecto a OUT 0. Busca un valor que funcione para OUT 0.

¿Te ha sido útil o tienes dudas? Deja tu comentario en 🐦 Twitter!

🐦 @RoamingWorkshop

TurfJS: herramientas geoespaciales interactivas para tus mapas web

Si has usado software GIS de escritorio, te sorprenderá saber que muchas de esas herramientas geoespaciales también están disponibles para tus mapas web mediante una librería javascript gratuita y de código abierto.

Hoy te enseño TurfJS. Pulsa el botón 🌤 del mapa incrustado y verás una de sus muchas posibilidades: la interpolación por inverso de la distancia al cuadrado o IDW.

Instalación

TurfJS cuenta con una práctica web que nos explica todas las funciones disponibles, así como la configuración inicial:

https://turfjs.org/getting-started

Para usar Turf sólo necesitamos enlazar la librería a nuestro mapa usando el enlace CDN que dan en su web:

<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>

Mapa base

Puedes crear un mapa base, por ejemplo, con Leaflet. Además, TurfJS utiliza sintaxis JSON, por lo que es altamente compatible con las funciones geoJSON de Leaflet.

TIP! Leaflet ha sido recientemente actualizado a la versión 1.9.1. Este post todavía no está actualizado y utiliza la versión 1.7.1.

Yo voy a reciclar este ejemplo de uno de mis primeros posts con algunos cambios:

  • Añado el enlace a la librería Turf en el <head>.
  • Defino los marcadores en una matriz o array de datos, similar a como se obtendrían de una fuente de datos en formato JSON:

https://www.w3schools.com/js/js_arrays.asp

var markers=[
{"name":"Estacion1",
"lat":25.77,
"lon":-80.13,
"dato":26.4},
{"name":"Estacion2",
"lat":25.795,
"lon":-80.21,
"dato":29.8},
{"name":"Estacion3",
"lat":25.70,
"lon":-80.275,
"dato":31.35}
];

TIP! Los valores numéricos NO irán "entrecomillados", o de lo contrario Turf los reconocerá como String (en Leaflet no ocurre).

  • Añado los marcadores al mapa con un bucle, usando la función forEach(), muy habitual para estos casos:

https://www.w3schools.com/jsref/jsref_foreach.asp

markers.forEach(function(m){
    var marker=L.marker([m.lat, m.lon]).addTo(map);
    marker.bindTooltip("<b>"+m.name+"</b><br>"+m.dato).openTooltip();
});

//ASÍ AÑADÍAMOS UN MARCADOR ÚNICO A LEAFLET
//var marker = L.marker([25.77, -80.13]).addTo(map);
//marker.bindTooltip("<b>Estacion1</b><br>m.dato").openTooltip();

Quedando así:

y siendo éste su código:

<head>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
  integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
  crossorigin=""/>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"
  integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
  crossorigin=""></script>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
</head>

<style>
#map{border-radius: 30px;}
</style>

<body>
<div id="map" style="height:500px;"></div>
</body>

<script>
var map = L.map('map').setView([25.75, -80.2], 12);
L.tileLayer("http://a.tile.openstreetmap.org/{z}/{x}/{y}.png", {/*no properties*/
}).addTo(map);

var markers=[
{"name":"Estacion1",
"lat":25.77,
"lon":-80.13,
"dato":26.4},
{"name":"Estacion2",
"lat":25.795,
"lon":-80.21,
"dato":29.8},
{"name":"Estacion3",
"lat":25.70,
"lon":-80.275,
"dato":31.35}
];

markers.forEach(function(m){
    var marker=L.marker([m.lat, m.lon]).addTo(map);
    marker.bindTooltip("<b>"+m.name+"</b><br>"+m.dato).openTooltip();
});
</script>

Interpolación IDW con TurfJS

En la forma anterior, los datos se pueden usar muy fácilmente con TurfJS.

Una de las herramientas más interesantes que facilita Turf es la interpolación de los datos en una malla regular.

https://turfjs.org/docs/#interpolate

Esto lo hace empleando uno de los métodos más habituales: el inverso de la distancia al cuadrado (IDW) o inverse distance weighting para una potencia de 2.

IDW de Wikipedia

Seguimos el ejemplo que nos da la web de TurfJS:

  1. Convertir los datos a una capa de puntos de Turf, una FeatureCollection:

https://turfjs.org/docs/#featureCollection

//vector de puntos vacío
var points=[];

//bucle para rellenar el vector de puntos con los datos
markers.forEach(function(m){
    points.push(turf.point([m.lon, m.lat],{name: m.name, dato: m.dato}));
});

//convertir a featureCollection de Turf
points=turf.featureCollection(points);

TIP! Fíjate que Turf recibe las coordenadas en longitud-latitud, en lugar del habitual latitud-longitud!

  1. Definir las opciones de la interpolación, entre las que podemos elegir las siguientes:
    • gridType: o tipo de malla
      • points (puntos)
      • square (cuadrados)
      • hex (hexágonos)
      • triangle (triángulos)
    • property: propiedad (o campo) del objeto de puntos que contiene los valores a interpolar.
    • units: unidades espaciales usadas en la interpolación
      • miles: millas
      • kilometers: kilómetros
      • radians: radianes
      • degrees: grados
    • weight: peso o potencia a la que se eleva la distancia, habitualmente 2, aunque valores más altos darán un resultado más suavizado.
//opciones de interpolación: malla rectangular de la variable 'dato' en kilómetros usando potencia de 2

var options = {gridType: 'square', property: 'dato', units: 'kilometers', weight: 2};
  1. Por último, generar la malla interpolada y añadirla al mapa, siendo el valor numérico el tamaño de las celdas de la malla interpolada (0.5 Km):
//crear malla de Turf
var malla=turf.interpolate(points, 0.5, options);

//añadir a Leaflet
L.geoJSON(malla).addTo(map);

Siendo este el resultado (nada concluyente):

Dar formato a la malla y mostrar valores

Aunque no lo parezca, la interpolación está hecha, aunque no se está mostrando correctamente.

Voy a añadir una escala de color que represente los datos, y también a mostrar los valores al pasar por encima de las celdas. Para ello, modificamos las propiedades del objeto geoJSON de Leaflet:

  • style: función para modificar el estilo de los objetos, evaluando su valor.
  • onEachFeature: función que se añade a cada objeto para interactuar con él.

https://leafletjs.com/reference.html#geojson

https://leafletjs.com/examples/choropleth/

L.geoJSON(malla,{
  style:function(feature){
  var val=feature.properties.dato;
  if(val>30){
    return {fillColor: "orangered", fillOpacity: 0.5, weight:0};
  }else if(val>28 && val < 30){
    return {fillColor: "yellowgreen", fillOpacity: 0.5, weight:0};
  }else if(val>26 && val < 28){
    return {fillColor: "darkgreen", fillOpacity: 0.5, weight:0};
  }
},
onEachFeature:function(feature,layer){
  layer.on({
  mouseover:function(e){
    val=e.target.feature.properties.dato.toFixed(2);
    e.target.bindTooltip(val).openTooltip();
  }
  });
}
}).addTo(map);

Quedando así:

Y aquí el código completo:

<head>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
  integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
  crossorigin=""/>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"
  integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
  crossorigin=""></script>
<script src='https://unpkg.com/@turf/turf@6/turf.min.js'></script>
</head>

<style>
#map{border-radius: 30px;}
</style>

<body>
<div id="map" style="height:500px;"></div>
</body>

<script>
var map = L.map('map').setView([25.75, -80.2], 12);
L.tileLayer("http://a.tile.openstreetmap.org/{z}/{x}/{y}.png", {/*no properties*/
}).addTo(map);

var markers=[
{"name":"Estacion1",
"lat":25.77,
"lon":-80.13,
"dato":26.4},
{"name":"Estacion2",
"lat":25.795,
"lon":-80.21,
"dato":29.8},
{"name":"Estacion3",
"lat":25.70,
"lon":-80.275,
"dato":31.35}
];

markers.forEach(function(m){
    var marker=L.marker([m.lat, m.lon]).addTo(map3);
    marker.bindTooltip("<b>"+m.name+"</b><br>"+m.dato).openTooltip();
});

//Datos para interpolación de Turf
//vector de puntos vacío
var points=[];
//bucle para rellenar el vector de puntos con los datos
markers.forEach(function(m){
points.push(turf.point([m.lon, m.lat],{name: m.name, dato: m.dato}));
});
//convertir a featureCollection de Turf

points=turf.featureCollection(points);

//opciones de interpolación
var options = {gridType:"square",property:"dato",units:"kilometers",weight:2};

//crear malla de Turf
var malla=turf.interpolate(points, 0.5, options);

//añadir a Leaflet
malla=L.geoJSON(malla,{
  style:function(feature){
  var val=feature.properties.dato;
  if(val>30){
    return {fillColor: "orangered", fillOpacity: 0.5, weight:0};
  }else if(val>28 && val < 30){
    return {fillColor: "yellowgreen", fillOpacity: 0.5, weight:0};
  }else if(val>26 && val < 28){
    return {fillColor: "darkgreen", fillOpacity: 0.5, weight:0};
  }
},
onEachFeature:function(feature,layer){
  layer.on({
  mouseover:function(e){
    val=e.target.feature.properties.dato.toFixed(2);
    e.target.bindTooltip(val).openTooltip();
  }
  });
}
}).addTo(map);

</script>

Aplicaciones

Como ejemplo aplicado a datos reales, he modificado la librería leafMET para incorporar la interpolación y añadido isobandas.

Es el mapa que has visto al inicio y que puedes abrir en pantalla completa:

https://theroamingworkshop.cloud/leafMET/leafMET+Turf.html

Además, el código está disponible en github como variante de leafMET:

https://github.com/TheRoam/leafMET/tree/leafMET+Turf

Y eso es todo! Espero que te sea útil!

Cualquier duda o comentario te espero en 🐦 Twitter!

🐦 @RoamingWorkshop

endleZZ: un minijuego javascript de supervivencia zombi infinito y aleatorio

endleZZ es un minijuego desarrollado en javascript, haciéndolo disponible para cualquier dispositivo con un navegador web.

A pesar de ello, se puede jugar sin conexión, ejecutando localmente el archivo .html que encontrarás en github desde cualquier lugar.

https://github.com/TheRoam/endleZZ

La versión v0.1 es un lanzamiento de prueba-de-concepto con las principales funciones habilitadas para probarlas.

La última versión online siempre se publicará oficialmente en este servidor:

https://theroamingworkshop.cloud/endlezz

TIP! Descarga siempre los ficheros de la fuente oficial que enlace yo, su autor. No ejecutes un fichero compartido por teceros. El código javascript puede ser fácilmente manipulable con fines maliciosos.

Descripción

Eres un superviviente con munición ilimitada rodeado de zombis, cuánto aguantarás?

La aleatoriedad hace cada partida única: enemigos zombi aparecen aleatoriamente por los límites del mapa, con atributos aleatorios (velocidad y nivel), haciéndolos impredecibles.

Hay 4 niveles de zombi, haciéndolos más grandes y difíciles de matar (1×1, 2×2, 3×3, 4×4).

El juego es infinito siempre y cuando puedas seguir matando zombis.

Eso sí! Malgastar balas resta puntuación, así que mantén tus disparos certeros!

Instrucciones

  1. Clicka o toca un punto del mapa para disparar a ese lugar.
  2. Cada bala usada resta 1 punto (-1).
  3. Disparar a partes del cuerpo (verde claro) suma 1 punto (+1).
  4. Disparar a la cabeza (verde oscuro) suma 10 puntos (+10).
  5. El tiempo de supervivencia sumará puntos en futuras versiones.

Características

  • Multi-platforma.
  • Portable (fichero .html ejecutable)
  • Ultraligero: 20 KB.
  • Sin-conexión: descarga y juega localmente.
  • Supervivencia infinita.
  • Aparición de enemigos aleatoria.
  • Tiempo de aparición aleatorio.
  • Atributos de enemigos aleatorios.
    • Velocidad
    • Nivel
  • Enemigos modulares (multi-parte)
    • Cuerpo (verde claro)
    • Cabeza (verde oscuro)
  • Sistema de puntuación
    • (Hit) Disparo al cuerpo +1
    • (Kill) Disparo a la cabeza +10
    • (Bullet) Bala usada -1
    • (Time) Tiempo de supervivencia [No implementado]
  • Animaciones

Futuros lanzamientos

Lluvia de ideas de características para futuras versiones:

  • menu de opciones
  • página resumen de puntuación final
  • gráficos más complejos
  • ciclo día-noche
  • sistema climático: nubes, lluvia, relámpagos
  • objetos de mapa: árboles, muros
  • enemigos complejos
  • saqueo de enemigos (balas, puntos)
  • poderes: ralentizar, matar todo el mapa, muerte a un disparo, etc

Desarrollo

Visita la página de desarrollo del juego en github

https://github.com/TheRoam/endleZZ

Si tienes ideas, preguntas o comentarios puedes dejarlos en 🐦 Twitter!

🐦 @RoamingWorkshop

Usando la API de datos abiertos de AEMET OpenData

En este post explicaba directamente cómo añadir las estaciones de AEMET con ciertos datos, usando mi plugin leafMET para Leaflet (disponible en github):

https://github.com/TheRoam/leafMET

Vamos a detenernos ahora en el detalle de cómo funciona la API y cómo acceder a todos los datos disponibles.

Acceso a la API

Para usar la API necesitamos una clave de acceso, o API key. Accedemos a la página de AEMET OpenData y hacemos click en el botón "Solicitar" debajo de Obtención de API key.

A continuación se nos pedirá una dirección de correo electrónico para enviarnos dicha clave.

Nos enviarán un primer correo de confirmación, y a continuación recibiremos un segundo correo con la clave de acceso. La copiamos y seguimos.

Documentación y ejemplos

Volvemos a la página de AEMET OpenData y entramos al Acceso Desarrolladores.

Nos interesa la documentación dinámica, que muestra todas las peticiones de datos disponibles y que podemos probar directamente desde allí.

Podemos pulsar sobre cada tema y se mostrará la sintaxis a usar para cada petición de datos.

Vamos a desplegar observación-convencional y, dentro, /api/observacion/convencional/todas.

Veremos un icono de aviso rojo a la derecha, donde podemos introducir la API key y probar la petición.

Ahora pulsamos el botón Try it out! y nos dará:

  • un ejemplo de petición curl
  • la URL de la petición
  • el cuerpo, código y encabezados de la respuesta

Si abrimos la dirección URL que nos ofrece el campo "datos" veremos el listado completo de datos de todas las estaciones. A mi me sale todo este chorizo de JSON:

Cargando...

Los campos más interesantes son los siguientes:

  • idema: ID o código de la estación.
  • lat y lon: coordenadas de latitud y longitud.
  • alt: altitud de la estación.
  • fint: fecha del intervalo (horario) de los datos.
  • prec: precipitación registrada en ese periodo.
  • vv: velocidad del viento en la estación.
  • ta: temperatura ambiente en la estación

Petición de datos para web mediante javascript

Estructura HTML

Voy a desarrollar un ejemplo incrustado para acceder a los datos y hacer uso de ellos. Simplemente creo un documento .html con un botón de solicitud y una línea de texto y una función de solicitud:

Pulsa el botón para solicitar los datos

<html>
<body>
<button id="solicitud" onclick="solicitar()">Solicitar</button>
<p id="texto">Pulsa el botón para solicitar los datos</p>
</body>
<script>
function solicitar(){
document.getElementById("texto").innerHTML="Todavía no he programado eso..";
}
</script>
</html>

TIP! Copia y pega este código en un documento de texto con extensión .html para abrirlo en tu navegador.

Solicitud HTTP

Realizamos la solicitud de datos con javascript usando el objeto XMLHttpRequest. En w3schools nos ponen un ejemplo muy simple:

https://www.w3schools.com/js/js_ajax_http.asp

Como vimos usando la documentación dinámica, después de hacer la solicitud, recibimos un enlace para acceder a los datos, lo cual es otra solicitud, así que debemos anidar dos solicitudes así:

<script>
function solicitar(){
// Definir texto de carga
document.getElementById("texto").innerHTML="Cargando datos...";
// Definir la API Key
var AK=tUApiKey;
// Definir URLs de solicitud
var URL1="https://opendata.aemet.es/opendata/api/observacion/convencional/todas";
var URL2="";

// Crear objetos XMLHttpRequest
const xhttp1 = new XMLHttpRequest();
const xhttp2 = new XMLHttpRequest();

// Definir función de respuesta a la primera solicitud:
// Queremos acceder a la URL del campo "datos"
xhttp1.onload = function() {
  // 1º Pasamos la respuesta a JSON:
  URL2=JSON.parse(this.responseText);
  // 2º Obtenemos el campo "datos":
  URL2=URL2.datos;  
  // 3º Hacemos la nueva petición:
  xhttp2.open("GET", URL2);
  xhttp2.send();
}

// Definir función de respuesta a la segunda solicitud:
// Modificaremos la línea de texto de la página con información descargada
xhttp2.onload = function() {
  // 1º Pasamos la respuesta a JSON (se trabaja mejor así):
  var datos=JSON.parse(this.responseText);

  // 2º Obtenemos la longitud del objeto JSON
  // Esto equivale a registros horarios individuales por estaciones
  var registros=datos.length;

  // 3º Obtenemos la fecha del primer registro.
  // Le daremos un formato más legible ya que está en ISO
  var fechaini=datos[0].fint;
  fechaini=new Date(fechaini+"Z");
  fechaini=fechaini.toLocaleDateString()+" "+fechaini.toLocaleTimeString();

  // 4º Obtenemos la fecha del último registro
  // Le damos el mismo formato
  var fechafin=datos[(datos.length-1)].fint;
  fechafin=new Date(fechaini+"Z");
  fechafin=fechafin.toLocaleDateString()+" "+fechafin.toLocaleTimeString();

  // 5º Unimos la información en la línea de texto
  document.getElementById("texto").innerHTML="Se han descargado <b>"+registros+"</b> registros desde el <b>"+fechaini+"</b> hasta el <b>"+fechafin+"</b>. <a href='"+URL2+"' target='_blank'>Ver todos los datos.</a>";
}

// Enviar la solicitud
xhttp1.open("GET", URL1+"/?api_key="+AK);
xhttp1.send();

}
</script>

Veamos el resultado a continuación:

Pulsa el botón para solicitar los datos

Y ya está listo! De esta forma puedes obtener las coordenadas y los valores de las distintas variables meteorológicas horarias de AEMET para usarlas en una tabla o en un mapa web como hemos visto para Leaflet.

Como siempre, deja tus dudas o comentarios en Twitter! 🐦

CesiumJS: el visor gratuito de mapas en 3D para tu web

El pasado julio, la revista Nature publicaba un Modelo Digital de Superficies en alta definición de la nueva orografía creada por el volcán Tajogaite de La Palma durante su erupción en el año 2021. Un trabajo espectacular del Istituto Nazionale di Geofisica e Vulcanologia junto con el Instituto Vulcanológico de Canarias.

Lo habitual es ver y trabajar con estos ficheros en algún programa de SIG como QGIS o ArcGIS, pero ¿cómo lo acercamos al resto de usuarios ?¿No sería mejor verlo directamente en 3D y visitarlo virtualmente?

Aquí es donde me topé con CesiumJS: un visor de mapas en 3D al estilo del famoso [G] Earth, pero de código abierto, gratuito y altamente personalizable para hacer tus propios proyectos.

Demo del visor CesiumJS con la nueva cartografía del volcán Tajogaite con imagen satelital de IDE Canarias. Clicka en el mapa para interactuar con él, o ábrelo en su versión completa.

Crear cuenta de Cesium ion

Para utilizar CesiumJS es necesario registrar una cuenta para crear un código de acceso o Access Token.

Además, registrándonos podremos subir nuestros propios ficheros y personalizar las vistas 3D que crearemos. Verás que en mi caso he subido el Modelo Digital de Superficies y la imagen satélite que usa el visor. Dejo aquí los enlaces por si quieres usar los mismos:

TIP! Puedes usar el servicio WMS en tu visor GIS para obtener una ortofoto completa, o descargar la que uso yo para este ejemplo (270 MB con resolución de 1m)

Incorporar CesiumJS a tu web.

Para usar CesiumJS configuramos un fichero .html como ya viene siendo habitual.

En este caso voy a copiar directamente uno de sus ejemplos ya que apenas tiene unas 25 líneas:

Como verás, las partes fundamentales son las siguientes:

  • enlaces a las librerías de CesiumJS en el <head>
  • un elemento <div> con id "cesiumContainer" dentro del <body>
  • el código de acceso dentro de la variable Cesium.Ion.defaultAccessToken. Introduce aquí la tuya.
  • una variable de visor llamada "viewer"
  • la configuración inicial del visor, especificando las coordenadas iniciales, y los ángulos de inclinación X y Z.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <!-- Include the CesiumJS JavaScript and CSS files -->
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.97/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.97/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
  <div id="cesiumContainer"></div>
  <script>
    // Your access token can be found at: https://cesium.com/ion/tokens.
    // This is the default access token from your ion account
    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1MTYwNGM0Yi1iYzlkLTRkMTUtOGQyOS04YjQxNmUwZDQ0YjkiLCJpZCI6MTA0Mjc3LCJpYXQiOjE2NjAxMDk4MzR9.syNWeKPLWA2eMrEh4K9hvkyp1oGdbLMaL0Ozk1kaksk';
    // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
    const viewer = new Cesium.Viewer('cesiumContainer', {
      terrainProvider: Cesium.createWorldTerrain()
    });    
    // Add Cesium OSM Buildings, a global 3D buildings layer.
    const buildingTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings());   
    // Fly the camera to San Francisco at the given longitude, latitude, and height.
    viewer.camera.flyTo({
      destination : Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400),
      orientation : {
        heading : Cesium.Math.toRadians(0.0),
        pitch : Cesium.Math.toRadians(-15.0),
      }
    });
  </script>
 </div>
</body>
</html>

TIP! También puedes descargar las librerías de CesiumJS y usarlas de forma local o en tu servidor.

Añadir un terreno personalizado

Seguimos los pasos de la página de Cesium:

  • En tu cuenta de Cesium ion, añadimos un nuevo terreno en Add data.
  • Seleccionamos el fichero y elegimos el tipo de datos Raster Terrain
  • Dentro de las opciones de terreno, elegimos como terreno base Main Sea Level y dejamos el resto por defecto.
  • Al subirse el fichero, ya nos aparecerá un extracto de código para usar este nuevo terreno.

Añadir ortofoto

Repetimos lo anterior, en este caso subiendo el fichero de imagen satélite y eligiendo el tipo de datos Raster Imagery.

En este caso, también se nos indica un extracto de código para utilizar dicha imagen.

Personalizando el visor final

Añadimos todo esto a nuestro fichero .html y lo personalizamos a nuestro gusto. Por ejemplo podemos:

  • Ajustar los elementos contenedores para que ocupen toda la pantalla:
<body style="margin:0;width:100vw;height:100vh;">
<div style="height:100%;" id="cesiumContainer"></div>
  • Esconder los controles inferiores:
viewer.timeline.container.style.visibility = "hidden";
viewer.animation.container.style.visibility = "hidden";
  • Modificar las coordenadas de la vista inicial para centrarla en nuestro emplazamiento:
viewer.camera.flyTo({
    destination : Cesium.Cartesian3.fromDegrees(-17.8195, 28.6052, 3000),
    orientation : {
    heading : Cesium.Math.toRadians(-85.0),
    pitch : Cesium.Math.toRadians(-30.0),
    }
});

El resultado ya lo habrás visto en varias ocasiones:

Y su código completo es este:

<html lang="en">
<head>
<meta charset="utf-8">

<script src="https://cesium.com/downloads/cesiumjs/releases/1.96/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.96/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body style="margin:0;width:100vw;height:100vh;">
<div style="height:100%;" id="cesiumContainer"></div>
<script>
    // Your access token can be found at: https://cesium.com/ion/tokens.
    // Replace `your_access_token` with your Cesium ion access token.

    Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1MTYwNGM0Yi1iYzlkLTRkMTUtOGQyOS04YjQxNmUwZDQ0YjkiLCJpZCI6MTA0Mjc3LCJpYXQiOjE2NjAxMDk4MzR9.syNWeKPLWA2eMrEh4K9hvkyp1oGdbLMaL0Ozk1kaksk';

    // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
    const viewer = new Cesium.Viewer('cesiumContainer', {
      //terrainProvider: Cesium.createWorldTerrain()//terreno original
		terrainProvider: new Cesium.CesiumTerrainProvider({//terreno modificado
			url: Cesium.IonResource.fromAssetId(1255858),
		}),	  
    });    
	
	// Esconder widgest inferiores
	viewer.timeline.container.style.visibility = "hidden";
	viewer.animation.container.style.visibility = "hidden";
	
	// Add Sentinel2 imagery
	const layer = viewer.imageryLayers.addImageryProvider(
	  new Cesium.IonImageryProvider({ assetId: 1256129 })
	);
    // Add Cesium OSM Buildings, a global 3D buildings layer.
    const buildingTileset = viewer.scene.primitives.add(Cesium.createOsmBuildings());   
    // Fly the camera to San Francisco at the given longitude, latitude, and height.
    viewer.camera.flyTo({
      destination : Cesium.Cartesian3.fromDegrees(-17.8195, 28.6052, 3000),
      orientation : {
        heading : Cesium.Math.toRadians(-85.0),
        pitch : Cesium.Math.toRadians(-30.0),
      }
    });
  </script>
</div>
</html>

Y esto es todo! Verás que puedes crear infinidad de aplicaciones web inmersivas con terrenos detallados por los usuarios y más precisos que los genéricos.

¿Se te ocurre qué más hacer con CesiumJS? Cuéntalo en Twitter 🐦

🐦 @RoamingWorkshop

Editor de texto interactivo para tus web apps con Rich Text Editor

Uno de mis últimos proyectos es una app de notas para alojarlas en mi servidor y prescindir de [G] Notes.

La característica más interesante que incluye es Rich Text Editor, una completa librería javascript en forma de interfaz para dar formato HTML al texto de cualquier formulario web.

Es de código abierto, gratis para uso personal, y muy simple de usar. Todo un win-win que te traigo hoy.

Licencia

He dicho que Rich Text Editor es gratis, y es así si le das un uso no comercial.

Es importante que leas su página de precios para que entiendas las limitaciones de la licencia gratuita:

  • 1 desarrollador
  • 1 dominio
  • 5 usuarios activos

En mi caso, he instalado Rich Text Editor en este servidor que aloja el blog, y lo he restringido mediante php para que solo se pueda acceder desde el propio dominio.

TIP! No hospedes los archivos en cualquier sitio que sea accesible por cualquiera (como un servidor público), ya que podrías dar pie a un incumplimiento de licencia, teniendo que pagar una licencia standard, o dando de baja tu app.

Aun así, las licencias comerciales son de un único pago y puede que te merezca la pena obtener una si vas a darle más uso.

Instalación

Usar Rich Text Editor es muy sencillo, y su página de documentación lo explica a la perfección.

Para instalar Rich Text Editor solo tenemos que descargar los ficheros de su página web a una carpeta local o a una ubicación de tu servidor.

https://richtexteditor.com/download.aspx

Habilitar interfaz

Rich Text Editor funciona dentro de un documento HTML.

Para habilitarlo:

  1. Como siempre, creamos un fichero HTML con su estructura básica.
  2. Enlazamos los scripts y el CSS en el <head> :

    <link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />  
    <script type="text/javascript" src="/richtexteditor/rte.js"></script>  
    <script type="text/javascript" src='/richtexteditor/plugins/all_plugins.js'></script>  

  3. Dentro del <body> añadimos el siguiente <div> :

    <div id="div_editor1" > 
    <p>Initial Document Content</p> 
    </div>

  4.   Por último, llamamos al editor en el <script> :

    var editor1 = new RichTextEditor("#div_editor1", {skin:"rounded-corner", toolbar:"full"});

Todo lo anterior se vería así (puedes interactuar con él):

Y aquí el código completo:

<html>
<head>

<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />
<script type="text/javascript" src="/richtexteditor/rte.js"></script>
<script type="text/javascript" src='/richtexteditor/plugins/all_plugins.js'></script

</head>
<body>

<div id="div_editor1" > 
<p>Initial Document Content</p> 
</div> 

</body>
<script>

var editor1 = new RichTextEditor("#div_editor1", {skin:"rounded-corner", toolbar:"full"});

</script>
</html>

TIP! Copia y pega el código anterior en un fichero .html, dentro de la carpeta de richtexteditor, y podrás ver este ejemplo en tu navegador.

Configuración

Como verás, he añadido algunas propiedades a la hora de llamar al editor:

{skin:"rounded-corner", toolbar:"full"}

Hay múltiples opciones de configuración que puedes consultar aquí:

https://richtexteditor.com/docs/configuration-reference.aspx

Funciones del editor

La librería contiene múltiples funciones en forma de API para interactuar con el editor. Todos los comandos que se pueden usar se encuentran aquí:

https://richtexteditor.com/docs/cmd_allcommands.aspx

Una funcionalidad básica es capturar el texto que hemos ido editando en el cuadro de texto. Es lo que hace el botón de la parte inferior, usando la función getHTMLcode():

<button onclick="alert(editor1.getHTMLCode())">Show Html Code</button>

Usos

Como comenté anteriormente, el uso que le voy a dar a esta librería es en un editor de notas que se alojará en mi servidor.

El editor de texto me sirve para dar formato a las notas muy fácilmente y guardarlas con todo el formato.

Aquí tienes una demo de cómo va quedando la interfaz, aunque no tiene las funciones habilitadas todavía.

Otras aplicaciones en las que puedes usar este editor es en foros, formularios, o cualquier cuadro de texto que tenga que rellenar un usuario de tu web app.

Espero que te resulte tan útil como a mí y que le des buen uso. Si tienes dudas o comentarios puedes enviarlos por Twitter 🐦 Hasta pronto!

🐦 @RoamingWorkshop

« Entradas anteriores Entradas siguientes »

© 2026 The Roaming Workshop

Tema por Anders NorenArriba ↑