Limitar posibles valores en una función a través de @Anotaciones.

Limitar los posibles valores que puede recibir una función a través de @Anotaciones, nos ayudará a determinar valores en constantes sin la necesidad de utilizar valores de tipo ENUM y prevenir posibles errores (un valor que no corresponda a la función) en tiempo de compilación.

Agregamos la dependencia a nuestro proyecto

compile 'com.android.support:support-annotations:24.2.1'

Definimos nuestros posibles valores en constantes

public static final int YES = 1;
public static final int NO = -1;

Definimos nuestra @anotación con las constantes antes mencionadas

@IntDef({YES, NO})
@Retention(RetentionPolicy.SOURCE)
public @interface OptionValues {}

Podemos especificar un valor por defecto

@OptionValues int currentOption = NO;

Creamos nuestro accesador y mutador

public void setCurrentOption(@OptionValues int currentOption) {
    this.currentOption = currentOption;
}
@OptionValues public int getCurrentOption() {
    return currentOption;
}

Y así ya podemos asignar un valor

setCurrentOption(YES);

Aquí todo el código del ejemplo

public class MainActivity extends Activity {
	public static final int YES = 1;
    public static final int NO = -1;

	@IntDef({YES, NO})
    @Retention(RetentionPolicy.SOURCE)
    public @interface OptionValues {}

	@OptionValues int currentOption = NO;

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setCurrentOption(YES);
	}

	public void setCurrentOption(@OptionValues int currentOption) {
        this.currentOption = currentOption;
    }
 
    @OptionValues
    public int getCurrentOption() {
        return currentOption;
    }
}

Vista para nuestras listas vacías en Android

Durante mi vida como desarrollador Android, he visto las formas más ingeniosas de mostrar vistas cuando una lista (ListView o RecyclerView) están vacías; desde frames ocultos en el layout, listas que empujan otros view con match_parent, entre otros.
Por suerte para estos males y otros, desde la versión del API 1, existe la función setEmptyView que recibe como parámetro un objeto View, que será mostrada cuando la el listView no contenga elementos.

View emptyView = getLayoutInflater().inflate(R.layout.empty_view, null);
ListView listView = (ListView)findViewById(R.id.listView);
listView.setEmptyView(emptyView);

Ahora respecto a los RecyclerView, en la documentación oficial no encontré una forma tan simple para poder resolverlo, por lo que hay que volver a las viejas andanzas y utilizar los famosos setVisibility en un frame que cubra toda la pantalla.

FrameLayout emptyView = (FrameLayout)findViewById(R.layout.empty_view);
MyRecyclerAdapter listAdapter = new MyRecyclerAdapter(listItems);
listAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
  @Override
  public void onChanged() {
    super.onChanged();
    if (listAdapter.getItemCount() == 0) {
      emptyView.setVisibility(View.VISIBLE);
    } else {
      emptyView.setVisibility(View.GONE);
    }
  }
});

Si conocen una forma mejor de poder mostrar una vista en un RecyclerView vacío, por favor compártanla para mejorar el tip.
Gracias!

Verificar si tenemos conexión a Internet en Android

Para verificar si estamos conectados a Internet, lo primero que tenemos que hacer es agregar el permiso ACCESS_NETWORK_STATE a nuestro archivo AndroidManifest.xml para así consultar el estado de nuestra conexión.

<uses-permission 
	android:name="android.permission.ACCESS_NETWORK_STATE" />

Luego creamos una función que a través del contexto en el cuál estemos trabajando verifique en el servicio CONNECTIVITY_SERVICE si estamos conectados o conectándonos. Esta función es estática para que pueda ser accesada desde cualquier parte sin necesidad te pertenecer a una instancia y debería estar ubicada en una clase Singleton o similar.

static public boolean isNetworkingAvailable(Context c){
	ConnectivityManager cm = 
		(ConnectivityManager)c.getSystemService(Context.CONNECTIVITY_SERVICE);

	NetworkInfo activeNetwork = cm.getActiveNetworkInfo();

	return activeNetwork != null && 
		activeNetwork.isConnectedOrConnecting();
}

Eventualmente si estamos conectados a una red que no tiene salida a Internet, podemos capturar el evento al momento de realizar algún request. Pero siempre deberíamos consultar primero con este servicio.

EditText con sugerencias de autocompletado en Android

AutoCompleteTextView

En este post crearemos un elemento EditText, que al momento que vayamos escribiendo palabras sobre este, nos vaya sugiriendo coincidencias obtenidas de un arreglo de palabras definidos por nosotros mismos anteriormente, como pueden ver a continuación.
Lo primero que tenemos que hacer es agregar el elemento EditText en la vista de nuestra Activity, que en este caso se llama AutoCompleteTextView.

<AutoCompleteTextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/autocomplete_region" android:layout_width="fill_parent" android:layout_height="wrap_content" />

Luego debemos crear la lista de las sugerencias que ofreceremos al usuario, esto debemos hacerlo en el archivo res/values/strings.xml. Recuerden que las etiquetas <resources></resources> son la raíz del archivo, por lo que si tienen más strings definidos deben ir también dentro de estas etiquetas.

<resources>
  <string-array name="region_array">
    <item>Región Metropolitana</item>
    <item>Región de Aríca y Parinacota</item>
    <item>Región de Tarapacá</item>
    <item>Región de Antofagasta</item>
    <item>Región de Atacama</item>
    <item>Región de Coquimbo</item>
    <item>Región de Valparaíso</item>
    <item>Región de O\'Higgins</item>
    <item>Región de Maule</item>
    <item>Región del Biobío</item>
    <item>Región de la Araucanía</item>
    <item>Región de los Ríos</item>
    <item>Región de los Lagos</item>
    <item>Región de Aysén</item>
    <item>Región de Magallanes y Antártica</item>
  </string-array>
</resources>

A continuación, dentro de la función onCreate, partimos referenciando el elemento AutoCompleteTextView que creamos anteriormente en la vista. Luego obtenemos las regiones que creamos en el archivos de string y creamos un adaptador ArrayAdapter que viene por defecto en Android. Cabe señalar que el elemento android.R.layout.simple_list_item_1 es también una vista que viene con el mismo android. Nosotros también podríamos crear nuestro propio adaptador extendiendo de ArrayAdapter (o de cualquier similar) y crear nuestra propia vista para los elementos que se desplieguen. Con lo que finalmente le pasamos el adaptador al elemento en la vista.

// Referencia al elemento en la vista
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autocomplete_region);

// Arreglo con las regiones
String[] regions = getResources().getStringArray(R.array.region_array);

// Le pasamos las regiones al adaptador
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, regions);

// finalmente le asignamos el adaptador a nuestro elemento
textView.setAdapter(adapter);

Recuerden que pueden consultar la documentación completa de AutoCompleteTextView ya que dispone de muchas funcionalidades para que podemos utilizar.

Espero que les haya servido y saludos!.

Cómo referenciar nuestras vistas y recursos con Butter Knife en Android

buttlerknife

Butter Knife es una excelente librería que nos ayudará a ahorrar código al momento de referenciar elementos de nuestras vistas, recursos del proyecto o hasta referencias eventos que interactúan con el usuario, utilizando connotaciones para cada una de estas.
Para comenzar, compilamos la librería en nuestro archivo gradle con las siguientes dependencias

compile 'com.jakewharton:butterknife:8.0.1'

Normalmente referenciamos elementos de nuestras vistas de la siguiente forma

class ExampleActivity extends Activity {
  TextView textViewName;
  TextView textViewCity;

  @Override 
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    textViewName = (TextView)findViewById(R.id.textViewName);
    textViewCity = (TextView)findViewById(R.id.textViewCity);
  }
}

Con la librería Butter Knife podríamos hacerlo así

class ExampleActivity extends Activity {
  @BindView(R.id.textViewName) TextView title;
  @BindView(R.id.textViewCity) TextView subtitle;

  @Override 
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    ButterKnife.bind(this);
  }
}

Si estamos dentro de un fragment pasamos la vista a la instancia de ButterKnife

View view = inflater.inflate(R.layout.fragment, container, false);
ButterKnife.bind(this, view);

Es importante liberar la memoria utilizada, una vez que destruyamos el fragment.

// ...
private Unbinder unbinder;
// ...

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  View view = inflater.inflate(R.layout.fragment, container, false);
  unbinder = ButterKnife.bind(this, view);
  return view;
}
@Override 
public void onDestroyView() {
  super.onDestroyView();
  unbinder.unbind();
}

Y a su vez también disponemos de otras connotaciones para para referenciar los recursos de nuestro proyecto, utilizando @BindBool, @BindColor, @BindDimen, @BindDrawable, @BindInt, @BindString

@BindString(R.string.title) String title;
@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red;
@BindDimen(R.dimen.left_margin) Float left_margin;

Podemos asignar eventos a los elementos de la vista

@OnClick(R.id.buttonSubmit) void submit() {
  // Aquí nuestro código...
}

Pasar la vista como parámetro

@OnClick(R.id.buttonSubmit) void submit(View view) {
  // Aquí nuestro código...
}

O pasar la posición si corresponde

@OnItemClick(R.id.list_of_things) void onItemClick(int position) {
  // Aquí nuestro código...
}

Tenemos disponible los siguientes eventos para asignar: @OnLongClick, @OnPageChange, @OnTextChanged, @OnTouch, @OnItemLongClick y @OnCheckedChanged. Incluso asignar el evento a varios elementos de una sola vez

@OnClick(R.id.buttonOne, R.id.buttonTwo, R.id.buttonThree)
public void submit(View view) {
  // Aquí nuestro código...
}

Podemos hacer listas de vistas y aplicar propiedades

@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;

ButterKnife.apply(nameViews, View.ALPHA, 0.0f);
ButterKnife.apply(nameViews, View.VISIBLE, false);
ButterKnife.apply(nameViews, DISABLE, false);

Finalmente podemos especificar que un elemento de la vista puede ser nulo al momento de referenciarlo o opcional al momento de asignar un evento.

@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;

@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
  // Nuestro código...
}

Espero que el post haya sido de ayuda y no duden en comentar sus dudas o sugerencias. Saludos!

Conectarse a socket.io de NodeJS con Android

logo android

Lo primero es agregar la dependencia de la librería a nuestro archivo grade en nuestro proyecto en Android Studio.

compile 'com.github.nkzawa:socket.io-client:0.4.0'

Así en la actividad que queramos utilizar el socket creamos el objeto Socket.

Socket socket;

y algunas constantes que utilizaremos en nuestro código.

final static String URL_SOCKET = "http://localhost";
final static String MY_EVENT = "my event";
final static String PARAM_NAME = "name";
final static String PARAM_IMAGE = "image";

Instanciamos nuestra conexión al servidor pasando como parámetro la url de este mismo.

try{
  /* Instance object socket */
  socket = IO.socket(URL_SOCKET);
}catch (URISyntaxException e){
  e.printStackTrace();
}

Podemos instanciar el objecto con opciones predeterminadas para que se reconecte el socket.

IO.Options opts = new IO.Options();
opts.forceNew = true;
opts.reconnection = false;
try{
  /* Instance object socket */
  socket = IO.socket(URL_SOCKET, opts);
}catch (URISyntaxException e){
  e.printStackTrace();
}

O para utilizar conexiones SSL por defecto o como parámetro al instanciar el objeto

/* Default SSLContext for all sockets */
IO.setDefaultSSLContext(mySSLContext);

/* Set as an option */
opts = new IO.Options();
opts.sslContext = mySSLContext;
try{
  /* Instance object socket */
  socket = IO.socket(URL_SOCKET, opts);
}catch (URISyntaxException e){
  e.printStackTrace();
}

Luego creamos los eventos principales de nuestro socket: EVENT_CONNECT y EVENT_DISCONNECT, estos son los que recibirán las emisiones desde el servidor.

socket.on(Socket.EVENT_CONNECT, new Emitter.Listener(){
  @Override
  public void call(Object... args) {
    /* Our code */
  }
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener(){
  @Override
  public void call(Object... args) {
    /* Our code */      
  }
});

Y crear nuestros propios eventos listener

socket.on(MY_EVENT, new Emitter.Listener(){
  @Override
  public void call(Object... args) {
    /* Our code */      
  }
});

Con esto ya podemos abrir la conexión

socket.connect();

Además disponemos de otras funciones como para verificar el estado de la conexión.

socket.connected()

Para desconectar nuestro socket.

socket.disconnect()

Si lo que queremos es emitir eventos por nuestro socket utilizamos, enviando cadenas de texto o también datos binarios.

JSONObject obj = new JSONObject();
obj.put(PARAM_NAME, "Pablo");
obj.put(PARAM_IMAGE, new byte[42]);

/* Emit event */
socket.emit(MY_EVENT, obj)

También podemos capturar el callback que retorna el servidor

socket.emit(MY_EVENT, obj, new Ack() {
  @Override
  public void call(Object... args) {
    /* Our code */
  }
});

Y eso es todo, Saludos!

Cambiar el tema de un fragment en Android

logo androidEstoy programando mucho en Android, pero no he subido nada al respecto, por lo que iré compartiendo pequeños códigos para hacer cosas especificas, que también claro, servirán para anotaciones personales mias.
Los fragment estan inmersos en las actividades que los contienen, por lo que no podemos cambiarlos directamente en el archivo AndroidManifest.xml, así que heredan los estilos que las actividades tengan definidas, y si estas últimas no tienen ningún tema definido heredan el que tenga la aplicación. Pero podemos cambiar esto utilizando las siguientes 3 lineas dentro de la función onCreateView de nuestro fragment.
Primero traemos el tema que queremos aplicar al fragment creando un objeto de contexto. Deben reemplazar MyAppTheme por su tema.

final Context themeWrapper = 
	new ContextThemeWrapper(getActivity(), R.style.MyAppTheme);

Luego definimos un LayoutInflater al cuál le aplicamos nuestro contexto anterior.

LayoutInflater cloneInflate = 
	inflater.cloneInContext(themeWrapper);

Y finalmente inflamos el layout de nuestro fragment utilizando el layout inflate definido anteriormente. Recuerden que deben reemplazar fragment_layout por el que corresponda con su fragment, y que será el que finalmente retornaremos en la función.

View view = 
	cloneInflate.inflate(R.layout.fragment_layout, container, false);

Eso es todo! Saludos!

Matemáticas, física y animación con Canvas html5 – parte 2

canvas
Estimados! Disculpen por dejar tanto tiempo el blog botado, ahora continuaré con los ejercicios de canvas. Este post es la continuación de Matemáticas, física y animación con Canvas html5 – parte 1. Para esta ocación no profundizaré tanto en puntos matemáticos como lo hice en la primera parte, por lo que recomiendo que si no la han leído lo hagan y luego continuen con esta.
Para este ejercicio vamos a crear muchas pelotas chocando con las paredes (no entre si) y moviendose a diferentes velocidades según el tamaño de cada una.
Si quieren ver el resultado bajen al final de este post
Al igual que el post anterior, comenzaré pegando todo el código para que lo vean y luego explicando cada uno de los puntos relevantes.
Comenzamos importando nuestra librería modernizr entre las etiquetas “head” de nuestro HTML para garantizar la compatibilidad de nuestro canvas con todos los navegadores.

<script src="http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.1/modernizr.min.js"></script>

y dentro de nuestras etiquetas body creamos el canvas donde se dibujará nuestro script.

<div>
	<canvas id="canvasTwo" width="600" height="300"> 
		Cambiate de navegador!
	</canvas>
</div>

Ahora el código completo de nuestro javascript

window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded(){
  canvasAppPartTwo();
}
function canvasSupport(){
  return Modernizr.canvas;
}
function canvasAppPartTwo(){
  if(!canvasSupport()){
    return;
  }

  function drawScreen(){
    context.fillStyle = '#EEEEEE';
    context.fillRect(0, 0, theCanvas.width, theCanvas.height);
    context.strokeStyle = '#000000';
    context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);
    
    var ball;
	for(var i = 0; i < balls.length; i++){
      ball = balls[i];
      context.fillStyle = ball.color;
      ball.x += ball.xunits;
      ball.y += ball.yunits;

      context.beginPath();
      context.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2, true);
      context.closePath();
      context.fill();

	  if((ball.x+ball.radius) > theCanvas.width || ball.x < 0){       
        ball.angle = 180 - ball.angle;       
        updateBall(ball);     
      }else if((ball.y+ball.radius) > theCanvas.height || ball.y < 0){
        ball.angle = 360 - ball.angle;
        updateBall(ball);
      }
	}
  }
  function updateBall(ball){
	ball.radians = ball.angle * Math.PI/ 180;
    ball.xunits = Math.cos(ball.radians) * ball.speed;
    ball.yunits = Math.sin(ball.radians) * ball.speed;
  }

  var numBalls = 1000;
  var maxSize = 8;
  var minSize = 5;
  var maxSpeed = maxSize + 5;
  var balls = new Array();
  var tempBall;
  var tempX;
  var tempY;
  var tempSpeed;
  var tempAngle;
  var tempRadius;
  var tempRadians;
  var tempXunits;
  var tempYunits;
  var tempColor;

  theCanvas = document.getElementById('canvasTwo');
  context = theCanvas.getContext('2d');

  for(var i = 0; i < numBalls; i++){
    tempRadius = Math.floor(Math.random()*maxSize)+minSize;
    tempX = tempRadius*2 + (Math.floor(Math.random()*theCanvas.width)-tempRadius*2);
    tempY = tempRadius*2 + (Math.floor(Math.random()*theCanvas.height)-tempRadius*2);
    tempSpeed = maxSpeed-tempRadius;
    tempAngle = Math.floor(Math.random()*360);
    tempRadians = tempAngle * Math.PI/ 180;
    tempXunits = Math.cos(tempRadians) * tempSpeed;
    tempYunits = Math.sin(tempRadians) * tempSpeed;
    tempColor = '#'+Math.floor(Math.random()*16777215).toString(16);
    tempBall = {
      x: tempX,
      y: tempY,
      radius: tempRadius,
      speed: tempSpeed,
      angle: tempAngle,
      xunits: tempXunits,
      yunits: tempYunits,
      color: tempColor
    }
    balls.push(tempBall);
  }
  setInterval(drawScreen, 33);
}

Ahora explicaré las cambios. Los primero es determinar la función que se ejecutará al momento que se cargue el javascript.

window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded(){
  canvasAppPartTwo();
}

Definimos un intervalo para ir ejecutando el canvas.

setInterval(drawScreen, 33);

Entonces en orden de ejecución debemos definir las variables que utilizares. Solo comentaré las nuevas que agregé a este ejemplo. Las demás son variables que utilizaremos de forma temporal.

var numBalls = 1000; // Numero de bolas
var maxSize = 8; // Tamaño máximo que pueden tener
var minSize = 5; // Tamaño minimo
var maxSpeed = maxSize + 5; // Velocidad máxima
var balls = new Array(); // Arreglo que contendrá las bolas que creemos.

Rerefenciamos el canvas en el contexto de nuestro script

theCanvas = document.getElementById('canvasTwo');
context = theCanvas.getContext('2d');

Lo siguiente es hacer un “for” que recorrerá para crear cada una de las pelotas, para este ejemplo serán 1000 (pueden poner el número que quieran, solo sean considerados con su máquina).

for(var i = 0; i < numBalls; i++){

}

Con esto vamos creando lo valores temprales de nuestras bolas. No me detendré en este punto porque ya está explicado en el primero post como voy sacando los cálculos, la única diferencia es que voy jugando con valores random.
Así encontes calculamos el radio entre el tamaño minimo que determinamos y el máximo.

tempRadius = Math.floor(Math.random()*maxSize)+minSize;

Luego calculamos la posición de la bola dentro del canvas, el valor random es el tamaño del canvas menos su radio al cuadrado.

tempX = tempRadius*2 + (Math.floor(Math.random()*theCanvas.width)-tempRadius*2);
tempY = tempRadius*2 + (Math.floor(Math.random()*theCanvas.height)-tempRadius*2);

La velocidad que está directamente relacionada con el tamaño de la bola, ya que mientras más grande sea, más lento debe moverse.

tempSpeed = maxSpeed-tempRadius;

Y los cambios de angulos en la dirección de nuestra bola.

tempAngle = Math.floor(Math.random()*360);
tempRadians = tempAngle * Math.PI/ 180;
tempXunits = Math.cos(tempRadians) * tempSpeed;
tempYunits = Math.sin(tempRadians) * tempSpeed;

FinaLmente le damos un color random a la pelota para poder diferenciarlas unas de otras.

tempColor = '#'+Math.floor(Math.random()*16777215).toString(16);

Ya teniendo todos los valores, agregamos la pelota a nuestro arreglo de bolas.

tempBall = {
	x: tempX,
    y: tempY,
    radius: tempRadius,
    speed: tempSpeed,
    angle: tempAngle,
    xunits: tempXunits,
    yunits: tempYunits,
    color: tempColor
}
balls.push(tempBall);				

Ya dentro de la función drawScreen dibujamos el contenedor de nuestro canvas.

context.fillStyle = '#EEEEEE';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeStyle = '#000000';
context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);

Y volvemos a recorrer el arreglo de bolas para id dibujandolas dentro de nuestro canvas. Utilizaré la variable auxiliar ball donde iré referenciando cada bola.

var ball;
for(var i = 0; i < balls.length; i++){
								
}

Referenciamos los valores.

ball = balls[i];
ball.x += ball.xunits;
ball.y += ball.yunits;					

Y dibujamos la bola con su respectivo color y tamaño.

context.fillStyle = ball.color;
context.beginPath();
context.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2, true);
context.closePath();
context.fill();

Ahora capturo el momento en donde la bola debe cambiar su dirección para no salir del canvas. Llamando a la función updateBall.

if((ball.x+ball.radius) > theCanvas.width || ball.x < 0){       
	ball.angle = 180 - ball.angle;       
    updateBall(ball);     
}else if((ball.y+ball.radius) > theCanvas.height || ball.y < 0){
	ball.angle = 360 - ball.angle;
    updateBall(ball);
}

Al comienzo del for definimos una variable auxiliar que ahora utilizamos para poder actualizar la bola fuera del for.

function updateBall(ball){
	ball.radians = ball.angle * Math.PI/ 180;
    ball.xunits = Math.cos(ball.radians) * ball.speed;
    ball.yunits = Math.sin(ball.radians) * ball.speed;
}													

Y por fin el resultado final! Hay varias cosas que podemos mejorar, como por ejemplo que las pelotas choquen entre ellas. Haré una tercera parte para eso.
Gracias por su tiempo y por espero que el tutorial les haya gustado.

Actualiza tu browser por la chucha!

Ya está disponible la versión beta de Jaampr

jaampr_logo

Jaampr es un proyecto de red social para Android (por ahora) en el cual llevo un tiempo trabajando. Consiste en una red social de actividades georeferenciada donde las personas pueden compartir lo que hacen y otras pueden unirse o interactuar con ellas. Ahora está en un proceso de beta así que sería de gran ayuda si mandan su feedback o reportar errores. Gracias!

Canvas y WebGL usando Three.js

canvas
Siguiendo con los post de Canvas. Les mostraré un pequeño ejemplo de la utilización de Three.js, una librería de Canvas y WebGL muy sencilla de implementar.
Lo primero como siempre es importarla entre nuestras etiquetas head de nuestro html.

http://ajax.googleapis.com/ajax/libs/threejs/r67/three.min.js

Y creamos un div dentro de las etiquetas body del html con el id basicMoveWithThree donde se creará nuestro canvas. Además yo le especifiqué un ancho y un alto: style=”width: 600px; height: 400px;”.
Pegaré todo el código de este ejemplo y luego lo explicaré. Lo que haremos será crear un cubo con WebGL el cuál rotará sobre su mismo eje. Este es un ejemplo bastante sencillo, la idea es solo mostrar lo fácil que es utilizar esta librería.

window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded(){
  basicMoveWithThree();
}
function basicMoveWithThree(){
  var scene = new THREE.Scene();
  var camera = new THREE.PerspectiveCamera(25, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.z = 5;

  var renderer = new THREE.WebGLRenderer();
  renderer.setSize(600, 400);
  renderer.setClearColor('#f7f7f7', 1);
  document.getElementById('basicMoveWithThree').appendChild(renderer.domElement);

  var geometry = new THREE.BoxGeometry(1,1,1);
  var material = new THREE.MeshLambertMaterial({color: 'blue'});
  var cube = new THREE.Mesh(geometry, material);
  scene.add(cube);

  var ambientLight = new THREE.AmbientLight(0x000044);
  scene.add(ambientLight);      

  var directionalLight = new THREE.DirectionalLight(0xffffff);
  directionalLight.position.set(1, 1, 1).normalize();
  scene.add(directionalLight);

  var angularSpeed = 0.2; 
  var lastTime = 0;
  var render = function(){
    var time = (new Date()).getTime();
    var timeDiff = time - lastTime;
    var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;        
    cube.rotation.x += angleChange;
    cube.rotation.y += angleChange;
    lastTime = time;
    renderer.render(scene, camera);
    requestAnimationFrame(render);
  };

  render();
}

En la primera parte del código cargo la función que contendrá mi script (esto es rutinario de javascript) y llamo a la función basicMoveWithThree declarada más abajo.

window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded(){
  basicMoveWithThree();
}

Ahora ya la parte entretenida. Lo primero que debo hacer es crear una Escena donde si visualizará mi WebGL y es a esta donde se cargarán todos los elementos que vaya creando más adelante, y a su vez crear una cámara que será la perspectiva con la que veré la escena. Hay 3 tipos de cámaras: Camera, OrthographicCamera y PerspectiveCamera. Para este ejemplo usarémos la última, que recibe 4 parámetros:
– El campo de visión vertital de abajo hacia arriba en grados.
– Relación del aspecto del ancho dividido por la altura.
– Plano cercano.
– Plano lejano.
Y luego determino la posición de la cámara en grados.

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(25, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 5;

El paso siguiente es determinar la forma en que se renderizará el Canvas o el WebGL (para este caso será con WebGL), el tamaño del canvas, el color de fondo, la profundidad, la sombra, la gama, etc.
Hay 4 formas de renderizar: CanvasRenderer, WebGLRenderer, WebGLRenderTarget y WebGLRenderTargetCube.
Pero para este caso usaremos WebGLRenderer, con un tamaño de 600 de ancho y 400 de alto, y usé el color de fondo de mi blog #f7f7f7 (por defecto es negro).

var renderer = new THREE.WebGLRenderer();
renderer.setSize(600, 400);
renderer.setClearColor('#f7f7f7', 1);

Junto a crear la forma de renderizar debo especificar donde lo aplicaré, en este caso será a un div con id ‘basicMoveWithThree’.

document.getElementById('basicMoveWithThree').appendChild(renderer.domElement);

Ahora crearemos el cubo. Debemos especificar el tipo de figura que usaremos, estas pueden ser figuras geométricas o curvas. Geométricas pueden ser: BoxGeometry, CircleGeometry, CubeGeometry, CylinderGeometry, ExtrudeGeometry, IcosahedronGeometry, LatheGeometry, OctahedronGeometry, ParametricGeometry, PlaneGeometry, PolyhedronGeometry, RingGeometry, ShapeGeometry, SphereGeometry, TetrahedronGeometry, TextGeometry, TorusGeometry, TorusKnotGeometry y TubeGeometry.
Y los tipos de curvas pueden ser: ArcCurve, ClosedSplineCurve3, CubicBezierCurve, CubicBezierCurve3, EllipseCurve, LineCurve, LineCurve3, QuadraticBezierCurve, QuadraticBezierCurve3, SplineCurve y SplineCurve3.
Y así ya podemos espeficiar el tipo de material (o superficie) del cuál estará compuesto nuestro cubo. Estos pueden ser: LineBasicMaterial, LineDashedMaterial, Material, MeshBasicMaterial, MeshDepthMaterial, MeshFaceMaterial, MeshLambertMaterial, MeshNormalMaterial, MeshPhongMaterial, PointCloudMaterial, RawShaderMaterial, ShaderMaterial, SpriteCanvasMaterial y SpriteMaterial.
Es importante elegir bien el tipo de material de nuestros objetos ya que esto influirá si aplicamos otros aspectos al escenario como la luz. Para este ejemplo usaré MeshLambertMaterial y le pasaré el color azul como parámetro, la clase MeshLambertMaterial puede recibir varios parámetros como intensidad de la luz o la refracción.
Luego creamos el elemento pasandole el elemento geométrico y el material del cuál estará compuesto, para luego agregarlo al escenario definido anteriormente con la función ‘add’.

var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshLambertMaterial({color: 'blue'});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

También podemos trabajar con la luz y su dirección en el escenario. Los tipos de luz que podemos utilizar son: AmbientLight, AreaLight, DirectionalLight, HemisphereLight, Light, PointLight y SpotLight.
Para este ejemplo usaremos AmbientLight recibiendo como parámetro el color de la luz.

var ambientLight = new THREE.AmbientLight(0x000044);
scene.add(ambientLight);  

Y luego especificamos la dirección que tendrá la luz en la escena, también recibiendo el color de la luz.

var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);

El paso final es ejecutar la renderización, y especificar los movientos que queramos realizar sobre los objetos que agregamos a la escena. Podemos utilizar la diferencia del tiempo actual para controlar las revoluciones de rotación de los elementos (en mi caso del cubo). Y luego es importante ejecutar requestAnimationFrame(render); para que el Canvas o WebGL se aplique en forma de frames (se vuelva a llamar).

var angularSpeed = 0.2; 
var lastTime = 0;
var render = function () {
  var time = (new Date()).getTime();
  var timeDiff = time - lastTime;
  var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;        
  cube.rotation.x += angleChange;
  cube.rotation.y += angleChange;
  lastTime = time;
  renderer.render(scene, camera);
  requestAnimationFrame(render);
};
render();

Y así finalmente nuestro WebGL se vería así!

Recuerden que pueden consultar toda la información de la librería en la página oficial y si tienen alguna observación o mejora del ejemplo no duden en comentarla. Saludos!