June 19, 2012

Android: fix the Android 2.x CSS transform bug with translate3d() and scale()

There's a serious bug with the use of the CSS3 transform property in Android's webkit browser, specifically in Android versions 2.2 and 2.3. The problem is that the scale() property is discarded in the presence of translate3d() (and other applicable transform properties). I can confirm it doesn't happen in 2.1, and I'm not seeing it consistently in all versions/devices with 2.3.x. The bug is officially documented here. There is a workaround, unfortunate as the bug is, which is to separately apply the translate3d() property to an outer element, and scale() to an inner element, like so:

Markup:
<div class="outer">
  <div class="inner"></div>
</div>
CSS:
.outer {
  transform: translate3d(100px, 100px, 0px)
  -webkit-transform: translate3d(100px, 100px, 0px)
  /* add other vendor prefixes so all browsers handle your hack */
}

.inner {
  transform: scale(5)
  /* add vendor-prefixed property again */
}
This doesn't work with scale() on the outer element, and translate3d() on the inner element, for what it's worth.

May 27, 2012

CSS: Rotation animation with CSS3

Sometimes you want to continuously spin something on your web page. In my case I was spinning a .png image for a smooth loading indicator. The following CSS will spin any element:
/* rotation animation */
@-webkit-keyframes rotate {
  from { -webkit-transform:rotate(0deg); }
  to { -webkit-transform:rotate(360deg); }
}

@-moz-keyframes rotate {
  from { -moz-transform:rotate(0deg); }
  to { -moz-transform:rotate(360deg); }
}

@-ms-keyframes rotate {
  from { -ms-transform:rotate(0deg); }
  to { -ms-transform:rotate(360deg); }
}

@-o-keyframes rotate {
  from { -o-transform:rotate(0deg); }
  to { -o-transform:rotate(360deg); }
}

.rotating {
  -webkit-transform-origin: 50% 50%;
  -webkit-animation-name: rotate;
  -webkit-animation-duration: 1.5s;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear;
  -moz-transform-origin: 50% 50%;
  -moz-animation-name: rotate;
  -moz-animation-duration: 1.5s;
  -moz-animation-iteration-count: infinite;
  -moz-animation-timing-function: linear;
  -ms-transform-origin: 50% 50%;
  -ms-animation-name: rotate;
  -ms-animation-duration: 1.5s;
  -ms-animation-iteration-count: infinite;
  -ms-animation-timing-function: linear;
  -o-transform-origin: 50% 50%;
  -o-animation-name: rotate;
  -o-animation-duration: 1.5s;
  -o-animation-iteration-count: infinite;
  -o-animation-timing-function: linear;
}
Just add/remove the .rotating class to an element to start/stop the animation.

April 23, 2012

Processing: Flip a PImage horizontally

I needed a mirror image of a PImage in my Processing project, so I came up with this little snippet:
public PImage getReversePImage( PImage image ) {
 PImage reverse = new PImage( image.width, image.height );
 for( int i=0; i < image.width; i++ ){
  for(int j=0; j < image.height; j++){
   reverse.set( image.width - 1 - i, j, image.get(i, j) );
  }
 }
 return reverse;
}

April 12, 2012

Javascript: Array.splice() is "broken" in IE 8 and below

It's not exactly broken, because all of the Array.splice() documentation that I've found says that the first 2 parameters - (start index and delete count) - are required. However, it seems that most modern browsers allow the 2nd parameter to be optional, and IE9 has made this the case as well. By leaving the 2nd parameter off, it assumes that you passed in the length of the array and clears everything past the start index. I found the issue when using array.splice(0) to empty an array, but it wasn't getting emptied in IE7 and IE8. My confusion came from my past life as an ActionScript developer, where the 2nd delete count parameter was optional. From now on, I'll be using at least the 2 required parameters for legacy IE support.

March 23, 2012

Javascript: Remove duplicate values from an array

I did a Google search for different methods of removing duplicate values from an array, and I found a bunch of crappy algorithms that all returned a new array, rather than paring down the original array. So I wrote this, which wouldn't work on identical complex objects, but works great for primitive data types and objects stored by reference.
function removeDuplicates(arr) {
  arr.sort();
  var i = arr.length - 1;
  while (i > 0) {
    if (arr[i] === arr[i - 1]) arr.splice(i, 1);
    i--;
  }
}