<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3911337215074644290</id><updated>2012-01-25T21:14:45.394-07:00</updated><category term='mobile'/><category term='images'/><category term='graphic'/><category term='flash'/><category term='processing'/><category term='Phonegap'/><category term='block'/><category term='simulator'/><category term='encoding'/><category term='bug'/><category term='as3'/><category term='gestures'/><category term='placeholder'/><category term='actionscript 3'/><category term='idevice'/><category term='flash player 10'/><category term='parsing'/><category term='processing.org'/><category term='dimming'/><category term='array'/><category term='chrome'/><category term='setinterval'/><category term='cocoa'/><category term='objective-c'/><category term='location'/><category term='detection'/><category term='iphone'/><category term='css'/><category term='timer'/><category term='js'/><category term='function'/><category term='truetype'/><category term='video'/><category term='link'/><category term='email'/><category term='amazonaws'/><category term='iOS'/><category term='papervision'/><category term='actionscript'/><category term='uiview'/><category term='displayobject'/><category term='float'/><category term='UITextField'/><category term='wget'/><category term='generate'/><category term='xml'/><category term='shuffle'/><category term='crossdomain.xml'/><category term='google maps'/><category term='toggle'/><category term='security'/><category term='scope'/><category term='ease'/><category term='format'/><category term='bash'/><category term='UISegmentedControl'/><category term='random number'/><category term='blur'/><category term='rotate'/><category term='style'/><category term='xcode'/><category term='problems'/><category term='flickr'/><category term='dim'/><category term='html'/><category term='base'/><category term='fp10'/><category term='actionscript 2'/><category term='OOP'/><category term='xmllist'/><category term='notification'/><category term='m4v'/><category term='egrep'/><category term='coffeescript'/><category term='pillowbox'/><category term='tween'/><category term='suffix'/><category term='attach'/><category term='value'/><category term='preload'/><category term='randomize'/><category term='ttf'/><category term='javascript'/><category term='uiimageview'/><category term='ipad'/><category term='weighted'/><category term='textfield'/><category term='input'/><category term='event'/><category term='502 error'/><category term='curl'/><category term='MPMoviePlayerController'/><category term='addsubview'/><category term='papervision3d'/><category term='string'/><category term='phone call'/><category term='nsnotification'/><category term='compression'/><category term='zoom'/><category term='node'/><category term='settimeout'/><category term='pinch'/><category term='webkit'/><category term='percentage'/><category term='shell'/><category term='itouch'/><category term='custom font'/><category term='animate'/><category term='physics'/><category term='canvas'/><category term='code'/><category term='letterbox'/><category term='Android'/><category term='touch'/><category term='subview'/><category term='focus'/><category term='fallback'/><category term='screen'/><category term='drawing'/><category term='php'/><category term='generative art'/><category term='static'/><category term='masking'/><category term='button'/><category term='easing'/><category term='bitmapdata'/><category term='gps'/><category term='Prototype.js'/><category term='regex'/><category term='jquery'/><category term='click'/><category term='textual'/><category term='hyperlink'/><category term='3D'/><category term='scrape'/><category term='ipod'/><category term='twitter'/><category term='as2'/><category term='uibutton'/><category term='IE'/><category term='command line'/><category term='landscape'/><category term='boolean'/><category term='bitmap'/><title type='text'>UI Hacker - Code for Fun</title><subtitle type='html'>A collection of handy code snippets in the languages that I use on a daily basis.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>66</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-3610827943876868520</id><published>2012-01-05T21:02:00.000-07:00</published><updated>2012-01-05T21:03:01.387-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='placeholder'/><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='coffeescript'/><category scheme='http://www.blogger.com/atom/ns#' term='focus'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='input'/><category scheme='http://www.blogger.com/atom/ns#' term='detection'/><category scheme='http://www.blogger.com/atom/ns#' term='fallback'/><category scheme='http://www.blogger.com/atom/ns#' term='blur'/><title type='text'>Coffeescript: HTML5 &lt;input&gt; placeholder attribute fallback</title><content type='html'>You want to use the new HTML5 &lt;b&gt;placeholder&lt;/b&gt; attribute on &lt;b&gt;input&lt;/b&gt; fields, but you also want to support older browsers. Here's a little Coffeescript class that takes an HTML element in the constructor, and uses jQuery to bind the &lt;b&gt;focus&lt;/b&gt; and &lt;b&gt;blur&lt;/b&gt; events to swap out text like a modern browser would without the script. &lt;pre&gt;&lt;br /&gt;# ## HTML5 placeholder feature fallback class&lt;br /&gt;class PlaceholderFallback&lt;br /&gt;&lt;br /&gt;  constructor: (el) -&gt;&lt;br /&gt;    @el = $(el)&lt;br /&gt;    @initialize()&lt;br /&gt;  &lt;br /&gt;  # HTML5 &amp;lt;input&amp;gt; placeholder feature detection&lt;br /&gt;  browserHasPlaceholder: =&gt;&lt;br /&gt;    "placeholder" of document.createElement("input")&lt;br /&gt;  &lt;br /&gt;  # Reads the placeholder attribute and uses it in a javascript fallback, if needed&lt;br /&gt;  initialize: =&gt;&lt;br /&gt;    if @browserHasPlaceholder() == false&lt;br /&gt;      placeholderText = @el.attr 'placeholder' &lt;br /&gt;      @el.removeAttr 'placeholder'&lt;br /&gt;      @el.val(placeholderText)&lt;br /&gt;      @el.focus (e) -&gt;&lt;br /&gt;        if this.value == placeholderText&lt;br /&gt;          this.value = ''&lt;br /&gt;      @el.blur (e) -&gt;&lt;br /&gt;        if this.value == ''&lt;br /&gt;          this.value = placeholderText&lt;br /&gt;    else&lt;br /&gt;      @el = null&lt;br /&gt;&lt;br /&gt;# Usage:&lt;br /&gt;placeholderFallback = new PlaceholderFallback( element )&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-3610827943876868520?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/3610827943876868520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2012/01/coffeescript-html5-placeholder.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3610827943876868520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3610827943876868520'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2012/01/coffeescript-html5-placeholder.html' title='Coffeescript: HTML5 &amp;lt;input&amp;gt; placeholder attribute fallback'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-334699109418118081</id><published>2011-12-19T20:24:00.001-07:00</published><updated>2011-12-19T20:32:24.140-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='pinch'/><category scheme='http://www.blogger.com/atom/ns#' term='click'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='gestures'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>CSS: Disable text selection highlighting</title><content type='html'>When working with touch &amp; mouse events to drag html elements, I've occasionally resorted to disabling clicking/touching on child elements by doing something like this:&lt;pre&gt;&lt;br /&gt;elem.onmousedown = function(e){ return false; };&lt;br /&gt;elem.onselectstart = function(){ return false; };&lt;br /&gt;&lt;/pre&gt;But sometimes you want to be able to interact with those child elements... I found some nice CSS &lt;a href="http://stackoverflow.com/questions/826782/css-rule-to-disable-text-selection-highlighting"&gt;over here&lt;/a&gt; that prevents text &amp; element highlighting when you're dragging with a mousemove or a touchmove event:&lt;pre&gt;&lt;br /&gt;p {&lt;br /&gt;  -webkit-user-select: none;&lt;br /&gt;  -khtml-user-select: none;&lt;br /&gt;  -moz-user-select: none;&lt;br /&gt;  -o-user-select: none;&lt;br /&gt;  user-select: none;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-334699109418118081?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/334699109418118081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/12/css-disable-text-selection-highlighting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/334699109418118081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/334699109418118081'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/12/css-disable-text-selection-highlighting.html' title='CSS: Disable text selection highlighting'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-85325037625180160</id><published>2011-12-11T22:36:00.001-07:00</published><updated>2011-12-11T22:46:20.908-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='coffeescript'/><category scheme='http://www.blogger.com/atom/ns#' term='Phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='google maps'/><title type='text'>Coffeescript: MapsLoader class for asynchronous loading of Google Maps API</title><content type='html'>I'm using CoffeeScript for my current project, and we needed a way to load the Google Maps API when a user hits a particular view. This static class is auto-initialized, and all you need to call is: &lt;b&gt;MapsLoader.load(callbackFunction,true)&lt;/b&gt;. If the API has already loaded, it will invoke your callback immediately. Make sure to pass the appropriate boolean if the user is on a mobile device (true), or a desktop browser (false). &lt;pre&gt;class MapsLoader&lt;br /&gt;&lt;br /&gt;  constructor: -&gt;&lt;br /&gt;&lt;br /&gt;  load: (successCallback,isMobileDevice) -&gt;&lt;br /&gt;    @isMobileDevice = isMobileDevice&lt;br /&gt;    @successCallback = successCallback&lt;br /&gt;    if @hasLoaded != true&lt;br /&gt;      @loadGoogle()&lt;br /&gt;    else&lt;br /&gt;      @mapsLoaded()&lt;br /&gt;&lt;br /&gt;  loadGoogle: =&gt;&lt;br /&gt;    # reference google loader callback to local method - clean up after callback&lt;br /&gt;    window.loadMaps = @loadMaps &lt;br /&gt;    apiKey = "-----your-api-key-here-----"&lt;br /&gt;    script = document.createElement("script")&lt;br /&gt;    script.src = "https://www.google.com/jsapi?key=#{apiKey}&amp;callback=loadMaps"&lt;br /&gt;    script.type = "text/javascript"&lt;br /&gt;    document.getElementsByTagName("head")[0].appendChild(script)&lt;br /&gt;&lt;br /&gt;  loadMaps: =&gt;&lt;br /&gt;    otherParams = if @isMobileDevice then "sensor=true" else "sensor=false"&lt;br /&gt;    google.load("maps", "3", {other_params: otherParams, "callback" : @mapsLoaded});&lt;br /&gt;&lt;br /&gt;  mapsLoaded: =&gt;&lt;br /&gt;    @hasLoaded = true&lt;br /&gt;    window.loadMaps = null&lt;br /&gt;    if @successCallback&lt;br /&gt;      @successCallback()&lt;br /&gt;    @successCallback = null&lt;br /&gt;&lt;br /&gt;@MapsLoader = new MapsLoader()&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-85325037625180160?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/85325037625180160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/12/coffeescript-mapsloader-class-for.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/85325037625180160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/85325037625180160'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/12/coffeescript-mapsloader-class-for.html' title='Coffeescript: MapsLoader class for asynchronous loading of Google Maps API'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1978946785437190108</id><published>2011-10-10T23:20:00.000-06:00</published><updated>2011-10-10T23:20:05.480-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='focus'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='input'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='blur'/><title type='text'>Javascript: Hide the iOS soft keyboard</title><content type='html'>I was having some trouble getting my text input field to relieve itself of focus on the iPhone, and after a little searching, I came up with a couple options. It's pretty self-explanatory. The 2nd line will de-focus all input fields, and it relies on jQuery. I found that calling blur() on the single focused textfield didn't always work. Either one of these lines should work independently, but both of them together cannot be stopped!&lt;pre&gt;&lt;br /&gt;var hideKeyboard = function() {&lt;br /&gt;	document.activeElement.blur();&lt;br /&gt;	$("input").blur();&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1978946785437190108?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1978946785437190108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/10/javascript-hide-ios-soft-keyboard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1978946785437190108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1978946785437190108'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/10/javascript-hide-ios-soft-keyboard.html' title='Javascript: Hide the iOS soft keyboard'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5015912858398264128</id><published>2011-09-25T22:38:00.000-06:00</published><updated>2011-09-25T22:43:36.597-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='ease'/><category scheme='http://www.blogger.com/atom/ns#' term='animate'/><category scheme='http://www.blogger.com/atom/ns#' term='easing'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='physics'/><title type='text'>Given distance and friction, calculate the initial velocity to stop at the distance target</title><content type='html'>While simulating iOS scroll views in javascript, I needed to find the initial velocity to send the scroll content back into position if you drag it out of bounds. Since the in-bounds scroll view inertia was already working with a given friction, I wanted to use this to run the calculation. After some brute-force experimenting, I came up with the equation to calculate this velocity:&lt;pre&gt;&lt;br /&gt;// set up vars&lt;br /&gt;var curPos = 0;&lt;br /&gt;var distance = 2000;&lt;br /&gt;var friction = 0.8;&lt;br /&gt;var velocity = distance / ( friction * ( 1 / ( 1 - friction ) ) );&lt;br /&gt;&lt;br /&gt;// in timer:&lt;br /&gt;setInterval(function(){&lt;br /&gt;    velocity *= friction;&lt;br /&gt;    curPos += velocity;&lt;br /&gt;},30);&lt;br /&gt;&lt;/pre&gt;The &lt;b&gt;curPos&lt;/b&gt; value will ease into the target &lt;b&gt;distance&lt;/b&gt;, no matter what you set as the &lt;b&gt;friction&lt;/b&gt; and &lt;b&gt;distance&lt;/b&gt;. Friction must be a decimal between zero and one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5015912858398264128?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5015912858398264128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/09/given-distance-and-friction-calculate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5015912858398264128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5015912858398264128'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/09/given-distance-and-friction-calculate.html' title='Given distance and friction, calculate the initial velocity to stop at the distance target'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1062517896409690145</id><published>2011-09-13T11:19:00.000-06:00</published><updated>2011-09-13T11:22:13.770-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='simulator'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='xcode'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='command line'/><category scheme='http://www.blogger.com/atom/ns#' term='Phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>Xcode error: "The argument is invalid"</title><content type='html'>If you get this error while publishing from Xcode, you may have a rogue symlink in your project. As of Xcode 4.1, symlinks will give you the awesome, helpful error:  "The argument is invalid"&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-lFoXpY_u0Xg/Tm-PdrJhpJI/AAAAAAAAAC0/TRx6fuKmWqo/s1600/argument-is-invalid.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="160" width="320" src="http://1.bp.blogspot.com/-lFoXpY_u0Xg/Tm-PdrJhpJI/AAAAAAAAAC0/TRx6fuKmWqo/s320/argument-is-invalid.png" /&gt;&lt;/a&gt;&lt;/div&gt;Check your project for symlinks, and remove them. If you're symlinking another directory into your project, this would work in the iOS Simulator, but not on a device, so you'd probably want to come up with another strategy for including files from another project. To help with finding symlinks, run the following command from the root of your project directory. It will list any symlinks and their original location.&lt;pre&gt;&lt;br /&gt;find ./ -type l -exec ls -l {} \;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1062517896409690145?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1062517896409690145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/09/xcode-error-argument-is-invalid.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1062517896409690145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1062517896409690145'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/09/xcode-error-argument-is-invalid.html' title='Xcode error: &quot;The argument is invalid&quot;'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-lFoXpY_u0Xg/Tm-PdrJhpJI/AAAAAAAAAC0/TRx6fuKmWqo/s72-c/argument-is-invalid.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6334655114954033994</id><published>2011-09-01T21:12:00.007-06:00</published><updated>2011-09-01T21:35:25.127-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='location'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='encoding'/><category scheme='http://www.blogger.com/atom/ns#' term='gps'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='google maps'/><category scheme='http://www.blogger.com/atom/ns#' term='compression'/><title type='text'>Google Maps API: Polyline encoding/decoding issue</title><content type='html'>I'm using google's &lt;a href="http://code.google.com/apis/maps/documentation/javascript/reference.html#encoding"&gt;Geometry Library&lt;/a&gt; to encode large numbers of GPS location points into a compressed format for storage. You can add this capability to your .js by adding it to the quersystring in the javascript reference:&lt;br /&gt;&lt;pre&gt;&amp;lt;script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=geometry&amp;sensor=true"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;The library provides a very easy way to display a path, add points realtime, &lt;a href="http://code.google.com/apis/maps/documentation/javascript/geometry.html#Encoding"&gt;store this path as an encoded &amp; compressed string&lt;/a&gt;, and feed that string back into a new map when you're ready to display it later. You can see a live example &lt;a href="http://code.google.com/apis/maps/documentation/javascript/examples/geometry-encodings.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Encoding works great, but I ran into an issue where some of my encoded paths, generated by &lt;b&gt;google.maps.geometry.encoding.encodePath()&lt;/b&gt; from my &lt;b&gt;google.maps.Polyline&lt;/b&gt; object, would have major errors when using the &lt;b&gt;google.maps.geometry.encoding.decodePath()&lt;/b&gt; method. My Polyline would have random right-angle turns that effectively ruined my path. I played around with the encoded string, trying to figure out what was causing the issue, to no avail. I found &lt;a href="http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/index.html"&gt;another implementation&lt;/a&gt; of the &lt;a href="http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html"&gt;polyline encoding algorithm&lt;/a&gt;, and found &lt;a href="http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/pitfalls.html"&gt;an explanation&lt;/a&gt; of what was causing the issue.&lt;br /&gt;&lt;br /&gt;It turns out that you need to escape the backslashes that may appear in the output string from  &lt;b&gt;google.maps.geometry.encoding.encodePath()&lt;/b&gt; (and the other library linked to above). So if you're storing the string for later, you want to do something like this:&lt;br /&gt;&lt;pre&gt;var encodedPath = google.maps.geometry.encoding.encodePath( _poly.getPath() ).replace(/\\/g,'\\\\');&lt;br /&gt;&lt;/pre&gt;You can then feed that encoded string into a new Map's Polyline instance like so:&lt;br /&gt;&lt;pre&gt;_poly.setPath( google.maps.geometry.encoding.decodePath( encodedPath ) );&lt;br /&gt;&lt;/pre&gt;It seems like an oversight that this double-backslash issue isn't mentioned in the Google documentation. I spent hours before trying to figure out the problem in my mobile app before coming across the fix.&lt;br /&gt;&lt;br /&gt;Finally, after you set a decoded path as the data for a Polyline, use the following code to fit the Map to the bounds of your path:&lt;br /&gt;&lt;pre&gt;var bounds = new google.maps.LatLngBounds();&lt;br /&gt;var path = _poly.getPath();&lt;br /&gt;path.forEach(function( latlng ) {&lt;br /&gt;	bounds.extend( latlng );&lt;br /&gt;});&lt;br /&gt;_map.fitBounds( bounds );	&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6334655114954033994?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6334655114954033994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/09/google-maps-api-polyline.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6334655114954033994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6334655114954033994'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/09/google-maps-api-polyline.html' title='Google Maps API: Polyline encoding/decoding issue'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6853002324267221682</id><published>2011-07-26T18:53:00.000-06:00</published><updated>2011-09-06T23:31:45.471-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='format'/><category scheme='http://www.blogger.com/atom/ns#' term='static'/><category scheme='http://www.blogger.com/atom/ns#' term='location'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='gps'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='google maps'/><title type='text'>Javascript: Formatting latitude/longitude location between Decimal and DMS (degrees, minutes, seconds)</title><content type='html'>I'm working on a javascript UI for a mobile app that receives location data in the Decmial format. We wanted the fancy DMS format, so I found some code, rewrote it, and wrapped it up into a nice little static class for converting back and forth.&lt;br /&gt;&lt;pre&gt;// A static class for converting between Decimal and DMS formats for a location&lt;br /&gt;// ported from: http://andrew.hedges.name/experiments/convert_lat_long/&lt;br /&gt;// Decimal Degrees = Degrees + minutes/60 + seconds/3600&lt;br /&gt;// more info on formats here: http://www.maptools.com/UsingLatLon/Formats.html&lt;br /&gt;// use: LocationFormatter.DMSToDecimal( 45, 35, 38, LocationFormatter.SOUTH );&lt;br /&gt;// or:  LocationFormatter.decimalToDMS( -45.59389 );&lt;br /&gt;&lt;br /&gt;function LocationFormatter(){&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;LocationFormatter.NORTH = 'N';&lt;br /&gt;LocationFormatter.SOUTH = 'S';&lt;br /&gt;LocationFormatter.EAST = 'E';&lt;br /&gt;LocationFormatter.WEST = 'W';&lt;br /&gt;&lt;br /&gt;LocationFormatter.roundToDecimal = function( inputNum, numPoints ) {&lt;br /&gt; var multiplier = Math.pow( 10, numPoints );&lt;br /&gt; return Math.round( inputNum * multiplier ) / multiplier;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;LocationFormatter.decimalToDMS = function( location, hemisphere ){&lt;br /&gt; if( location &lt; 0 ) location *= -1; // strip dash '-'&lt;br /&gt; &lt;br /&gt; var degrees = Math.floor( location );          // strip decimal remainer for degrees&lt;br /&gt; var minutesFromRemainder = ( location - degrees ) * 60;       // multiply the remainer by 60&lt;br /&gt; var minutes = Math.floor( minutesFromRemainder );       // get minutes from integer&lt;br /&gt; var secondsFromRemainder = ( minutesFromRemainder - minutes ) * 60;   // multiply the remainer by 60&lt;br /&gt; var seconds = LocationFormatter.roundToDecimal( secondsFromRemainder, 2 ); // get minutes by rounding to integer&lt;br /&gt;&lt;br /&gt; return degrees + '&amp;deg ' + minutes + "' " + seconds + '" ' + hemisphere;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;LocationFormatter.decimalLatToDMS = function( location ){&lt;br /&gt; var hemisphere = ( location &lt; 0 ) ? LocationFormatter.SOUTH : LocationFormatter.NORTH; // south if negative&lt;br /&gt; return LocationFormatter.decimalToDMS( location, hemisphere );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;LocationFormatter.decimalLongToDMS = function( location ){&lt;br /&gt; var hemisphere = ( location &lt; 0 ) ? LocationFormatter.WEST : LocationFormatter.EAST;  // west if negative&lt;br /&gt; return LocationFormatter.decimalToDMS( location, hemisphere );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;LocationFormatter.DMSToDecimal = function( degrees, minutes, seconds, hemisphere ){&lt;br /&gt; var ddVal = degrees + minutes / 60 + seconds / 3600;&lt;br /&gt; ddVal = ( hemisphere == LocationFormatter.SOUTH || hemisphere == LocationFormatter.WEST ) ? ddVal * -1 : ddVal;&lt;br /&gt; return LocationFormatter.roundToDecimal( ddVal, 5 );  &lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6853002324267221682?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6853002324267221682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/07/javascript-formatting-latitudelongitude.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6853002324267221682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6853002324267221682'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/07/javascript-formatting-latitudelongitude.html' title='Javascript: Formatting latitude/longitude location between Decimal and DMS (degrees, minutes, seconds)'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-863118866435345589</id><published>2011-04-27T00:08:00.001-06:00</published><updated>2011-04-27T00:26:21.184-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='itouch'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='ipod'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Webkit bug: translate3d positioning doesn't activate browser scrollbars</title><content type='html'>After some frustration in Safari and Mobile Safari, I found that by setting a -webkit-transform: translate3d() to position the y-coordinate of an html element beyond the browser window height, it will not cause the browser to activate its scrollbars. However, by switching to the web-standards css &lt;b&gt;top&lt;/b&gt; style, this problem is alleviated. This seems like a browser bug to me.&lt;br /&gt;&lt;br /&gt;Consider the following css, in both desktop and mobile Safari:&lt;br /&gt;&lt;pre&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;style&amp;gt;&lt;br /&gt;    .notbroken {&lt;br /&gt;      position:absolute;&lt;br /&gt;      top:10000px;&lt;br /&gt;    }&lt;br /&gt;    .broken {&lt;br /&gt;      position:absolute;&lt;br /&gt;      -webkit-transform: translate3d(0px, 10000px, 0px);&lt;br /&gt;    }&lt;br /&gt;  &amp;lt;/style&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;  &amp;lt;div class=&amp;quot;notbroken&amp;quot;&amp;gt;Scrollbars, please.&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;Both css classes position the div 10,000 pixels down the page, but if you use the &lt;b&gt;.broken&lt;/b&gt; version, you won't get scrollbars, and you'll never be able to see the content.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-863118866435345589?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/863118866435345589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/04/webkit-bug-translate3d-positioning.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/863118866435345589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/863118866435345589'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/04/webkit-bug-translate3d-positioning.html' title='Webkit bug: translate3d positioning doesn&apos;t activate browser scrollbars'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-8590270037783813687</id><published>2011-04-19T15:30:00.002-06:00</published><updated>2011-04-19T15:36:07.687-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='pinch'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='rotate'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='itouch'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='ipod'/><category scheme='http://www.blogger.com/atom/ns#' term='gestures'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><title type='text'>Javascript: Handle touch gestures for pinch (scale) and rotation</title><content type='html'>I wrote a little class to handle pinch &amp; rotate gestures on a web page in iOS. There's a bunch of event listener adding/removing, which can get a little messy, so this should help keep your code clean if you need to handle gestures.&lt;br /&gt;&lt;br /&gt;Here's the class:&lt;br /&gt;&lt;pre&gt;function GestureCallback( element, endCallback, changeCallback ) {&lt;br /&gt;  this.element = element;&lt;br /&gt;  this.end_callback = endCallback;&lt;br /&gt;  this.change_callback = changeCallback;&lt;br /&gt;  this.scale = 1;&lt;br /&gt;  this.rotation = 0;&lt;br /&gt;  this.init();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GestureCallback.prototype.init = function() {&lt;br /&gt;  // scope functions for listener removal&lt;br /&gt;  var self = this;&lt;br /&gt;  this.gestureStart = function(e){ self.onGestureStart(e) };&lt;br /&gt;  this.gestureChange = function(e){ self.onGestureChange(e) };&lt;br /&gt;  this.gestureEnd = function(e){ self.onGestureEnd(e) };&lt;br /&gt;  &lt;br /&gt;  // really no need to check for IE stupidness, but maybe they'll support gestures someday? oy.&lt;br /&gt;  if( this.element.attachEvent ) this.element.attachEvent( "touchstart", this.gestureStart ); else this.element.addEventListener( "touchstart", this.gestureStart, false );&lt;br /&gt;  if( this.element.attachEvent ) this.element.attachEvent( "gesturestart", this.gestureStart ); else this.element.addEventListener( "gesturestart", this.gestureStart, false );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;GestureCallback.prototype.onGestureStart = function ( e ) {&lt;br /&gt;  if( this.element.attachEvent ) this.element.attachEvent( "gesturechange", this.gestureChange ); else this.element.addEventListener( "gesturechange", this.gestureChange, false );&lt;br /&gt;  if( this.element.attachEvent ) this.element.attachEvent( "gestureend", this.gestureEnd ); else this.element.addEventListener( "gestureend", this.gestureEnd, false );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;GestureCallback.prototype.onGestureChange = function ( e ) {&lt;br /&gt;  this.scale = e.scale;&lt;br /&gt;  this.rotation = e.rotation;&lt;br /&gt;  if( this.change_callback ) this.change_callback( this.scale, this.rotation );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;GestureCallback.prototype.onGestureEnd = function ( e ) {&lt;br /&gt;  if( this.element.detachEvent ) this.element.detachEvent( "gesturechange", this.gestureChange ); else this.element.removeEventListener( "gesturechange", this.gestureChange, false );&lt;br /&gt;  if( this.element.detachEvent ) this.element.detachEvent( "gestureend", this.gestureEnd ); else this.element.removeEventListener( "gestureend", this.gestureEnd, false );&lt;br /&gt;&lt;br /&gt;  this.scale = e.scale;&lt;br /&gt;  this.rotation = e.rotation;&lt;br /&gt;  if( this.end_callback ) this.end_callback( this.scale, this.rotation );&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;GestureCallback.prototype.dispose = function() {&lt;br /&gt;  if( this.element.attachEvent ) this.element.detachEvent( "touchstart", this.gestureStart ); else this.element.removeEventListener( "touchstart", this.gestureStart, false );&lt;br /&gt;  if( this.element.attachEvent ) this.element.detachEvent( "gesturestart", this.gestureStart ); else this.element.removeEventListener( "gesturestart", this.gestureStart, false );&lt;br /&gt;  &lt;br /&gt;  this.element = null;&lt;br /&gt;  this.end_callback = null;&lt;br /&gt;  this.change_callback = null;&lt;br /&gt;  &lt;br /&gt;  this.gestureStart = null;&lt;br /&gt;  this.gestureChange = null;&lt;br /&gt;  this.gestureEnd = null;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;And the instantiation:&lt;br /&gt;&lt;pre&gt;var pinchCallback = new GestureCallback( yourElement, function( scale, rotation ){&lt;br /&gt;  console.log('done: '+scale+','+rotation);&lt;br /&gt;  if( scale &lt; 1 ) {&lt;br /&gt;    // leave the section, since we've pinched it closed&lt;br /&gt;  }&lt;br /&gt;}, function( scale, rotation ){&lt;br /&gt;  console.log('changing: '+scale+','+rotation);&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;And when you're done with your gesture needs, collect your garbage:&lt;pre&gt;pinchCallback.dispose();&lt;br /&gt;pinchCallback = null;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-8590270037783813687?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/8590270037783813687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/04/javascript-handle-touch-gestures-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8590270037783813687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8590270037783813687'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/04/javascript-handle-touch-gestures-for.html' title='Javascript: Handle touch gestures for pinch (scale) and rotation'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1048143937824777978</id><published>2011-04-08T00:48:00.001-06:00</published><updated>2011-04-08T10:28:23.658-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='processing.org'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='itouch'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='processing'/><title type='text'>Processing: MovieMaker gotchas in Eclipse</title><content type='html'>I haven't touched my Processing sketches for a while, and got lots of weird errors while trying to render a video using the built-in MovieMaker object.&lt;br /&gt;&lt;pre&gt;Exception in thread "Animation Thread" java.lang.UnsatisfiedLinkError: quicktime.QTSession.Gestalt(I[I)S&lt;br /&gt;Caused by: java.lang.UnsatisfiedLinkError: /System/Library/Java/Extensions/libQTJNative.jnilib:  no suitable image found.  Did find:  /System/Library/Java/Extensions/libQTJNative.jnilib: no matching architecture in universal wrapper&lt;br /&gt;&lt;/pre&gt;The above error was fixed by switching the JVM that Eclipse was using in the "Run..." configuration. On my Macbook, I simply switched to an alternate JVM 1.5, and it got rid of the problem:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-YVKy84Zv-UY/TZ6mKucSJ0I/AAAAAAAAABU/tAfa81Pb6xA/s1600/p5MMJVM-post.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="89" src="http://2.bp.blogspot.com/-YVKy84Zv-UY/TZ6mKucSJ0I/AAAAAAAAABU/tAfa81Pb6xA/s320/p5MMJVM-post.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;If you get the following error, you need to delete the previous rendered movie, or use some sort of timestamp to automatically name each new movie:&lt;br /&gt;&lt;pre&gt;The movie file already exists.  Please delete it first.&lt;br /&gt;&lt;/pre&gt;Here's a little timestamp code I wrote to help prevent file name conflicts:&lt;br /&gt;&lt;pre&gt;_timestamp = "" + String.valueOf( p.year() ) + "-" + String.valueOf( p.month() ) + "-" + String.valueOf( p.day() ) + "-" + String.valueOf(p.hour()) + "-" + String.valueOf(p.minute()) + "-" + String.valueOf(p.second());&lt;br /&gt;  &lt;br /&gt;_mm = new MovieMaker( p, p.width, p.height, "output/render-"+_timestamp+".mov", _framesPerSecond, MovieMaker.ANIMATION, MovieMaker.HIGH );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A stupid user-error error message I got was due to accidentally starting 2 instances of MovieMaker. Upon calling MovieMaker.finish(), I got this error:&lt;br /&gt;&lt;pre&gt;quicktime.std.StdQTException[QTJava:7.6.6g],-2014=invalidDuration,QT.vers:7668000&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Some other issues I've run into: &lt;br /&gt;* Certain codecs won't be installed on your machine. For example, I can't use MovieMaker.H264, but I can use MovieMaker.ANIMATION&lt;br /&gt;* After rendering a movie, Quicktime can have trouble playing it back, especially with certain codecs. My movies look blank. A workaround is to open and export the video from Quicktime Pro in order to view it.&lt;br /&gt;&lt;br /&gt;Finally, something I've been doing with all my Processing sketches is to add the following VM Arguments to the Run Configuration. This helps avoid running out of memory and to run in 32-bit mode (required for certain operations):&lt;br /&gt;&lt;pre&gt;-d32&lt;br /&gt;-Xmx1024M&lt;br /&gt;-Xms1024M&lt;br /&gt;&lt;/pre&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-cX_OzzvlrxU/TZ8zzU5IatI/AAAAAAAAABY/kD4R3PzBKwY/s1600/vmArgs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://1.bp.blogspot.com/-cX_OzzvlrxU/TZ8zzU5IatI/AAAAAAAAABY/kD4R3PzBKwY/s320/vmArgs.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1048143937824777978?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1048143937824777978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/04/processing-moviemaker-gotchas-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1048143937824777978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1048143937824777978'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/04/processing-moviemaker-gotchas-in.html' title='Processing: MovieMaker gotchas in Eclipse'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-YVKy84Zv-UY/TZ6mKucSJ0I/AAAAAAAAABU/tAfa81Pb6xA/s72-c/p5MMJVM-post.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2664228049477670660</id><published>2011-02-21T22:56:00.000-07:00</published><updated>2011-02-21T22:56:27.092-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='email'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><category scheme='http://www.blogger.com/atom/ns#' term='egrep'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><category scheme='http://www.blogger.com/atom/ns#' term='scrape'/><title type='text'>Bash script: Harvest email addresses from a directory of files</title><content type='html'>I had to go through over a year of server logs to rescue newsletter signups that may or may not have been passed to our newsletter service, due to server updates that happened without my knowledge. I wrote a little command to scrape all the log files in my directory, and output a text file with all the addresses it found. Here we go:&lt;br /&gt;&lt;pre&gt;# recursively(!) scrapes directories and prints out each email address to a new line&lt;br /&gt;egrep -o -h -r '[a-zA-Z0-9_-\+\.]+@[a-zA-Z0-9_-\+\.]+?\.[a-zA-Z]{2,3}' *.* | sort | uniq &gt; email_addresses.txt&lt;br /&gt;&lt;/pre&gt;Credit: I started with a &lt;a href="http://www.linux.com/archive/articles/54514"&gt;command from Linux.com&lt;/a&gt;, and customized it until the output was correct, and nicely formatted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2664228049477670660?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2664228049477670660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/02/bash-script-harvest-email-addresses.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2664228049477670660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2664228049477670660'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/02/bash-script-harvest-email-addresses.html' title='Bash script: Harvest email addresses from a directory of files'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-189353072294491672</id><published>2011-02-21T14:52:00.001-07:00</published><updated>2011-02-21T14:53:24.459-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>jQuery fadeIn() bug on iPad: element disappears</title><content type='html'>I'm using jQuery on a new site, and a fadeIn() animation broke, but only on the iPad with iOS 3.2.2. It works fine in every other browser, including the newer iOS (4+) for iPad. To fix the problem, which in my case doesn't affect other browsers, I simply added a callback function that manually sets the width and height of the element:&lt;br /&gt;&lt;pre&gt;newSection.fadeIn( 300 , function(){&lt;br /&gt;  newSection.css( { width:320, height:480 } );&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;I tried other css properties first, but width and height are the magic properties that prevent the element from being hidden. Quick, someone tell Steve Jobs :p&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-189353072294491672?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/189353072294491672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/02/jquery-fadein-bug-on-ipad-element.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/189353072294491672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/189353072294491672'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/02/jquery-fadein-bug-on-ipad-element.html' title='jQuery fadeIn() bug on iPad: element disappears'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5219343776635605826</id><published>2011-02-20T22:57:00.000-07:00</published><updated>2011-02-20T22:57:30.441-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='images'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmapdata'/><category scheme='http://www.blogger.com/atom/ns#' term='graphic'/><category scheme='http://www.blogger.com/atom/ns#' term='letterbox'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><category scheme='http://www.blogger.com/atom/ns#' term='pillowbox'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmap'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><category scheme='http://www.blogger.com/atom/ns#' term='displayobject'/><title type='text'>Actionscript 3: Grabbing and resizing BitmapData</title><content type='html'>I found this handy little class in a Flash project that I just had to jump back into. It's an easy way to take a bitmap snapshot of any DisplayObject, then resize the image data to fit another frame. You can fill the area, letterbox/pillowbox, or just scale to new dimensions. Feel free to use this, and nevermind the warnings that show up in FDT :)&lt;br /&gt;&lt;pre&gt;package com.cache.util &lt;br /&gt;{&lt;br /&gt; import flash.display.BitmapData;&lt;br /&gt; import flash.display.DisplayObject;&lt;br /&gt; import flash.geom.Matrix;&lt;br /&gt; import flash.geom.Point;&lt;br /&gt; import flash.geom.Rectangle;&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * @author justin - http://uihacker.blogspot.com/&lt;br /&gt;  */&lt;br /&gt;  &lt;br /&gt; public class ImageEdit &lt;br /&gt; {&lt;br /&gt;  /**&lt;br /&gt;   * Return a snapshot of a DisplayObject&lt;br /&gt;   */&lt;br /&gt;  public static function getBitmapData( vSource:DisplayObject, vW:Number=NaN, vH:Number=NaN, vTransparent:Boolean=true, vColor:int=0xFF00FF, vMatrix:Matrix=null ):BitmapData&lt;br /&gt;  {&lt;br /&gt;   // set defaults.&lt;br /&gt;   var vWidth:int = ( isNaN( vW )) ? vSource.width : vW;&lt;br /&gt;   var vHeight:int = ( isNaN( vH )) ? vSource.height : vH;  &lt;br /&gt;   &lt;br /&gt;   // create BitmapData object.&lt;br /&gt;   var vBmp:BitmapData = new BitmapData( vWidth, vHeight, vTransparent, vColor );&lt;br /&gt;   &lt;br /&gt;   // draw contents of source clip into target.&lt;br /&gt;   if ( vMatrix == null ) vBmp.draw( vSource, null, null, null, null, true );&lt;br /&gt;   else vBmp.draw( vSource, vMatrix, null, null, null, true ); &lt;br /&gt;   &lt;br /&gt;   return vBmp;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Build &amp; return a matrix to use to scale a bitmap&lt;br /&gt;   */&lt;br /&gt;  public static function getScaleMatrix( scale:Number ) : Matrix&lt;br /&gt;  {&lt;br /&gt;   var matrix:Matrix = new Matrix();&lt;br /&gt;   matrix.scale(scale, scale);&lt;br /&gt;   return matrix;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Pass these constants into the getResizedBitmapData() function&lt;br /&gt;   */&lt;br /&gt;  public static const RESIZE_SCALE:String = 'ImageEdit.resizeScale';&lt;br /&gt;  public static const RESIZE_LETTERBOX:String = 'ImageEdit.resizeLetterbox';&lt;br /&gt;  public static const RESIZE_CROP:String = 'ImageEdit.resizeCrop';&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Return a resized BitmapData copy of the original&lt;br /&gt;   */&lt;br /&gt;  public static function getResizedBitmapData( sourceBitmap:BitmapData, targetWidth:Number, targetHeight:Number, resizingMethod:String = '', disposeSourceBmp:Boolean = true ) : BitmapData&lt;br /&gt;  {&lt;br /&gt;   // get current dimensions&lt;br /&gt;   var curW:Number = sourceBitmap.width;&lt;br /&gt;   var curH:Number = sourceBitmap.height;&lt;br /&gt;   &lt;br /&gt;   // get ratios of 2 sides&lt;br /&gt;   var ratio_w:Number = targetWidth / curW;&lt;br /&gt;   var ratio_h:Number = targetHeight / curH;&lt;br /&gt;   var shorterRatio:Number = ( ratio_w &gt; ratio_h ) ? ratio_h : ratio_w;&lt;br /&gt;   var longerRatio:Number = ( ratio_w &gt; ratio_h ) ? ratio_w : ratio_h;&lt;br /&gt;   &lt;br /&gt;   &lt;br /&gt;   // apply sizing&lt;br /&gt;   switch( resizingMethod )&lt;br /&gt;   {&lt;br /&gt;    case RESIZE_CROP :&lt;br /&gt;     // get shorter ratio, so we fill the target area&lt;br /&gt;     var resizedWidth:int = Math.round( curW * longerRatio );&lt;br /&gt;     var resizedHeight:int = Math.round( curH * longerRatio );&lt;br /&gt;     &lt;br /&gt;     // create copy of, and resize the source bitmap&lt;br /&gt;     var resizedSourceBmp:BitmapData = new BitmapData( resizedWidth, resizedHeight, false, 0x00000000 );&lt;br /&gt;     // create scale matrix &lt;br /&gt;     var matrix:Matrix = new Matrix();&lt;br /&gt;     matrix.scale( longerRatio, longerRatio );&lt;br /&gt;     // take resized snapshot&lt;br /&gt;     resizedSourceBmp.draw( sourceBitmap, matrix );&lt;br /&gt;     &lt;br /&gt;     // draw into destination bitmap, letterbox/pillowbox style&lt;br /&gt;     var destBitmap:BitmapData = new BitmapData( targetWidth, targetHeight, false, 0x00000000 );&lt;br /&gt;     var offset:Point = new Point( targetWidth / 2 - resizedWidth / 2, targetHeight / 2 - resizedHeight / 2 );&lt;br /&gt;     destBitmap.copyPixels( resizedSourceBmp, new Rectangle( -offset.x, -offset.y, resizedSourceBmp.width, resizedSourceBmp.height ), new Point() );&lt;br /&gt;     &lt;br /&gt;     // clean up temp BitmapData&lt;br /&gt;     resizedSourceBmp.dispose();&lt;br /&gt;     if( disposeSourceBmp ) sourceBitmap.dispose();&lt;br /&gt;     &lt;br /&gt;     return destBitmap;&lt;br /&gt;     break;&lt;br /&gt;     &lt;br /&gt;    case RESIZE_LETTERBOX :&lt;br /&gt;     // get shorter ratio, so we fill the target area&lt;br /&gt;     var resizedWidth:int = Math.round( curW * shorterRatio );&lt;br /&gt;     var resizedHeight:int = Math.round( curH * shorterRatio );&lt;br /&gt;     &lt;br /&gt;     // create copy of, and resize the source bitmap&lt;br /&gt;     var resizedSourceBmp:BitmapData = new BitmapData( resizedWidth, resizedHeight, false, 0x00000000 );&lt;br /&gt;     // create scale matrix &lt;br /&gt;     var matrix:Matrix = new Matrix();&lt;br /&gt;     matrix.scale( shorterRatio, shorterRatio );&lt;br /&gt;     // take resized snapshot&lt;br /&gt;     resizedSourceBmp.draw( sourceBitmap, matrix );&lt;br /&gt;     &lt;br /&gt;     // draw into destination bitmap, letterbox/pillowbox style&lt;br /&gt;     var destBitmap:BitmapData = new BitmapData( targetWidth, targetHeight, false, 0x00000000 );&lt;br /&gt;     var pastePoint:Point = new Point( targetWidth / 2 - resizedWidth / 2, targetHeight / 2 - resizedHeight / 2 );&lt;br /&gt;     destBitmap.copyPixels( resizedSourceBmp, new Rectangle( 0, 0, resizedSourceBmp.width, resizedSourceBmp.height ), pastePoint );&lt;br /&gt;     &lt;br /&gt;     // clean up temp BitmapData&lt;br /&gt;     resizedSourceBmp.dispose();&lt;br /&gt;     if( disposeSourceBmp ) sourceBitmap.dispose();&lt;br /&gt;     &lt;br /&gt;     return destBitmap;&lt;br /&gt;     break;&lt;br /&gt;     &lt;br /&gt;    case RESIZE_SCALE :&lt;br /&gt;    default : &lt;br /&gt;     // create output bitmap&lt;br /&gt;     var vBmp:BitmapData = new BitmapData( targetWidth, targetHeight, false, 0x00000000 );&lt;br /&gt;     // create scale matrix &lt;br /&gt;     var matrix:Matrix = new Matrix();&lt;br /&gt;     matrix.scale( ratio_w, ratio_h );&lt;br /&gt;     // snapshot with scale &amp; return&lt;br /&gt;     vBmp.draw( sourceBitmap, matrix );&lt;br /&gt;     &lt;br /&gt;     // clean up temp BitmapData&lt;br /&gt;     if( disposeSourceBmp ) sourceBitmap.dispose();&lt;br /&gt;     &lt;br /&gt;     return vBmp;&lt;br /&gt;     break; &lt;br /&gt;     &lt;br /&gt;   }&lt;br /&gt;   return null;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5219343776635605826?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5219343776635605826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/02/actionscript-3-grabbing-and-resizing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5219343776635605826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5219343776635605826'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/02/actionscript-3-grabbing-and-resizing.html' title='Actionscript 3: Grabbing and resizing BitmapData'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-4094660952407125488</id><published>2011-02-07T17:48:00.001-07:00</published><updated>2011-02-07T17:50:39.240-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='masking'/><category scheme='http://www.blogger.com/atom/ns#' term='processing.org'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='graphic'/><category scheme='http://www.blogger.com/atom/ns#' term='drawing'/><category scheme='http://www.blogger.com/atom/ns#' term='processing'/><title type='text'>Processing: Shapes disappear when switching from P3D to OPENGL renderer</title><content type='html'>I was having some issues with my 3d scene in &lt;a href="http://processing.org"&gt;Processing&lt;/a&gt; when switching to OPENGL from the P3D rendering mode. At a certain distance, my shapes were disappearing in OPENGL, but they displayed properly in P3D. My good friend (and Processing whiz) &lt;a href="http://movax.us"&gt;Movax&lt;/a&gt; gave me the suggestion to adjust my &lt;a href="http://processing.org/reference/perspective_.html"&gt;perspective()&lt;/a&gt;. Theses we the value that helped my situation:&lt;br /&gt;&lt;pre&gt;perspective( 1.0f, 1.5f, 1f, 200000f );&lt;br /&gt;&lt;/pre&gt;The 200,000 value is the maximum depth that the camera will be able to see in OPENGL mode, which was large enough to view some of my distant objects that had been disappearing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-4094660952407125488?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/4094660952407125488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/02/processing-shapes-disappear-when.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4094660952407125488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4094660952407125488'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/02/processing-shapes-disappear-when.html' title='Processing: Shapes disappear when switching from P3D to OPENGL renderer'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-4917359820785349966</id><published>2011-01-24T01:54:00.001-07:00</published><updated>2011-01-24T01:56:11.997-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='curl'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='wget'/><category scheme='http://www.blogger.com/atom/ns#' term='shell'/><category scheme='http://www.blogger.com/atom/ns#' term='scrape'/><title type='text'>Bash shell script: Scraping and downloading image files from a ffffound RSS feed</title><content type='html'>I wrote this little script for a friend, as an exercise in bash shell scripting. This script is for OS X.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Step 1:&lt;/b&gt;&lt;br /&gt;&lt;a href="https://github.com/mxcl/homebrew/wiki/installation"&gt;Install &lt;b&gt;Homebrew&lt;/b&gt;&lt;/a&gt; - this is a great tool for installing common Unix tools. You should only have to open Terminal, and paste the 1-line installation script found in the link above. Something like this:&lt;br /&gt;&lt;pre&gt;ruby -e "$(curl -fsSLk https://gist.github.com/raw/323731/install_homebrew.rb)"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Step 2:&lt;/b&gt;&lt;br /&gt;Install &lt;b&gt;wget&lt;/b&gt; with Homebrew: type this into &lt;b&gt;Terminal&lt;/b&gt; and press Enter:&lt;br /&gt;&lt;pre&gt;brew install wget&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Step 3:&lt;/b&gt;&lt;br /&gt;Save the following code into a text file called "ffffound_sssswiped.sh" and save it into your User/Pictures/ directory:&lt;br /&gt;&lt;pre&gt;curl http://feeds.feedburner.com/ffffound/everyone | egrep -o source\ url=\"http://[^[:space:]]*.\(jpg\|png\|gif\) | egrep -o http://[^[:space:]]*.\(jpg\|png\|gif\) | xargs wget -nc -P ~/Pictures/ffffound&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Step 4:&lt;/b&gt;&lt;br /&gt;Customize! You can replace &lt;b&gt;http://feeds.feedburner.com/ffffound/everyone&lt;/b&gt; with your own ffffound RSS feed, or anyone else's. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Step 5:&lt;/b&gt;&lt;br /&gt;Run the script: type the following into Terminal, and hit Enter:&lt;br /&gt;&lt;pre&gt;bash ~/Pictures/ffffound_sssswiped.sh&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You should see the download progress as it scrapes the RSS feed for &lt;i&gt;just&lt;/i&gt; the large-format image files. You can run this as often as you want, and it will skip any files you've already downloaded. &lt;br /&gt;&lt;br /&gt;Magic!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-4917359820785349966?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/4917359820785349966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/01/bash-shell-script-scraping-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4917359820785349966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4917359820785349966'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/01/bash-shell-script-scraping-and.html' title='Bash shell script: Scraping and downloading image files from a ffffound RSS feed'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6842513357808622592</id><published>2011-01-19T21:37:00.000-07:00</published><updated>2011-01-19T21:37:19.799-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='screen'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='Phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><title type='text'>Android + Phonegap: Scale the WebView to fit the device</title><content type='html'>I was porting an iPad app to Android for the new Samsung tablet, and I had some trouble getting my web view to scale to the size of the device screen so that I wouldn't have to resize any of my assets. Obviously this is a questionable tactic, but I was experimenting and wanted to see how it would look :) &lt;br /&gt;&lt;br /&gt;Here's the meat of my main App.java class:&lt;br /&gt;&lt;pre&gt;public class App extends DroidGap {&lt;br /&gt; &lt;br /&gt; // declare the original size of the iPad app&lt;br /&gt; protected float ORIG_APP_W = 768;&lt;br /&gt; protected float ORIG_APP_H = 1004;&lt;br /&gt; &lt;br /&gt;    /** Called when the activity is first created. */&lt;br /&gt;    @Override&lt;br /&gt;    public void onCreate(Bundle savedInstanceState) {&lt;br /&gt;        super.onCreate(savedInstanceState);&lt;br /&gt;        super.loadUrl("file:///android_asset/www/index.html");&lt;br /&gt;        &lt;br /&gt;     // set some defaults&lt;br /&gt;     this.appView.setBackgroundColor(0x000000);&lt;br /&gt;     this.appView.setHorizontalScrollBarEnabled(false);&lt;br /&gt;     this.appView.setHorizontalScrollbarOverlay(false);&lt;br /&gt;     this.appView.setVerticalScrollBarEnabled(false);&lt;br /&gt;     this.appView.setVerticalScrollbarOverlay(false);&lt;br /&gt;     &lt;br /&gt;     // get actual screen size&lt;br /&gt;     Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();&lt;br /&gt;     int width = display.getWidth(); &lt;br /&gt;     int height = display.getHeight(); &lt;br /&gt;     &lt;br /&gt;     // calculate target scale (only dealing with portrait orientation)&lt;br /&gt;     double globalScale = Math.ceil( ( width / ORIG_APP_W ) * 100 );&lt;br /&gt;     &lt;br /&gt;     // make sure we're all good&lt;br /&gt;     Log.v( "ORIG_APP_W", " = " + ORIG_APP_W );&lt;br /&gt;     Log.v( "ORIG_APP_H", " = " + ORIG_APP_H );&lt;br /&gt;     Log.v( "width", " = " + width );&lt;br /&gt;     Log.v( "this.appView.getMeasuredHeight()", " = " + height );&lt;br /&gt;     Log.v( "globalScale", " = " + globalScale );&lt;br /&gt;     Log.v( "this.appView.getScale()", "index=" + this.appView.getScale() );&lt;br /&gt;    &lt;br /&gt;     // set some defaults on the web view&lt;br /&gt;     this.appView.getSettings().setBuiltInZoomControls( false );&lt;br /&gt;     this.appView.getSettings().setSupportZoom( false );&lt;br /&gt;     this.appView.getSettings().setGeolocationEnabled( true );&lt;br /&gt;     this.appView.getSettings().setLightTouchEnabled( true );&lt;br /&gt;     this.appView.getSettings().setRenderPriority( RenderPriority.HIGH );&lt;br /&gt;     &lt;br /&gt;     // set the scale&lt;br /&gt;     this.appView.setInitialScale( (int)globalScale );&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I also updated the AndroidManifest.xml file to lock the app into portrait orientation, work on tablet-sized devices, have a nice app name, and give the device access to the Internet and geolocation:&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;manifest xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;&lt;br /&gt;      package=&amp;quot;com.phonegap.testapp&amp;quot;&lt;br /&gt;      android:versionCode=&amp;quot;1&amp;quot;&lt;br /&gt;      android:versionName=&amp;quot;1.0&amp;quot;&amp;gt;     &lt;br /&gt;     &lt;br /&gt;    &amp;lt;application android:icon=&amp;quot;@drawable/icon&amp;quot; &lt;br /&gt;        android:label=&amp;quot;@string/app_name&amp;quot;&lt;br /&gt;        android:debuggable=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;        &amp;lt;activity android:name=&amp;quot;.App&amp;quot; &lt;br /&gt;                  android:label=&amp;quot;Test App&amp;quot; &lt;br /&gt;                  android:configChanges=&amp;quot;orientation|keyboardHidden&amp;quot;&lt;br /&gt;                  android:noHistory=&amp;quot;true&amp;quot; &lt;br /&gt;                  android:stateNotNeeded=&amp;quot;true&amp;quot; &lt;br /&gt;                  android:screenOrientation=&amp;quot;portrait&amp;quot;&amp;gt;&lt;br /&gt;            &amp;lt;intent-filter&amp;gt;&lt;br /&gt;                &amp;lt;action android:name=&amp;quot;android.intent.action.MAIN&amp;quot; /&amp;gt;&lt;br /&gt;                &amp;lt;category android:name=&amp;quot;android.intent.category.LAUNCHER&amp;quot; /&amp;gt;&lt;br /&gt;            &amp;lt;/intent-filter&amp;gt;&lt;br /&gt;        &amp;lt;/activity&amp;gt;&lt;br /&gt;    &amp;lt;/application&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;!-- allows access to phonegap hardware features --&amp;gt;&lt;br /&gt; &amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot; /&amp;gt;&lt;br /&gt; &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_NETWORK_STATE&amp;quot; /&amp;gt;&lt;br /&gt; &amp;lt;!--&amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_WIFI_STATE&amp;quot; /&amp;gt;--&amp;gt;&lt;br /&gt; &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_COARSE_LOCATION&amp;quot; /&amp;gt; &lt;br /&gt; &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_FINE_LOCATION&amp;quot; /&amp;gt;&lt;br /&gt; &amp;lt;uses-permission android:name=&amp;quot;android.permission.ACCESS_LOCATION_EXTRA_COMMANDS&amp;quot; /&amp;gt;&lt;br /&gt;    &amp;lt;uses-permission android:name=&amp;quot;android.permission.READ_PHONE_STATE&amp;quot; /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;supports-screens&lt;br /&gt;     android:largeScreens=&amp;quot;true&amp;quot;&lt;br /&gt;     android:normalScreens=&amp;quot;false&amp;quot;&lt;br /&gt;     android:smallScreens=&amp;quot;false&amp;quot;&lt;br /&gt;     android:resizeable=&amp;quot;true&amp;quot;&lt;br /&gt;     android:anyDensity=&amp;quot;true&amp;quot;&lt;br /&gt;     /&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/manifest&amp;gt; &lt;br /&gt;&lt;/pre&gt;And finally my res/layout/main.xml file, though I'm not sure if this is different from the Phonegap default:&lt;br /&gt;&lt;pre&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;br /&gt;&amp;lt;LinearLayout xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;&lt;br /&gt;    android:orientation=&amp;quot;vertical&amp;quot;&lt;br /&gt;    android:layout_width=&amp;quot;fill_parent&amp;quot;&lt;br /&gt;    android:layout_height=&amp;quot;fill_parent&amp;quot;&lt;br /&gt;    &amp;gt;    &lt;br /&gt;            &amp;lt;WebView android:id=&amp;quot;@+id/appView&amp;quot;&lt;br /&gt;            android:layout_height=&amp;quot;fill_parent&amp;quot;&lt;br /&gt;            android:layout_width=&amp;quot;fill_parent&amp;quot;&lt;br /&gt;            /&amp;gt; &lt;br /&gt;&amp;lt;/LinearLayout&amp;gt;&lt;br /&gt;&lt;/pre&gt;I hope this helps someone port their hybrid html5 iPad app to Android tablets.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6842513357808622592?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6842513357808622592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/01/android-phonegap-scale-webview-to-fit.html#comment-form' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6842513357808622592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6842513357808622592'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/01/android-phonegap-scale-webview-to-fit.html' title='Android + Phonegap: Scale the WebView to fit the device'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-4942269941730816525</id><published>2011-01-19T21:11:00.000-07:00</published><updated>2011-01-19T21:11:03.285-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='tween'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='animate'/><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Javascript: Clear a webkitTransition animation</title><content type='html'>I was animating an html element with Webkit transitions via javascript, and after the animation was done, I applied non-animated webkitTransform positioning to the same element. It animated instead of immediately displaying the new style. I came up with the following function to clear any previous Webkit animation values:&lt;br /&gt;&lt;pre&gt;function clearAnimation( element ) {&lt;br /&gt;  if( typeof element.style.webkitTransform !== 'undefined' &amp;&amp; element.style.webkitTransform ) {   // 2nd conditional fixes bug in Chrome on windows&lt;br /&gt;    element.style.webkitTransition = '';&lt;br /&gt;    element.style.webkitTransform = '';&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This will prevent any overlap when switching between animatiions and instant repositioning.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-4942269941730816525?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/4942269941730816525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/01/javascript-clear-webkittransition.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4942269941730816525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4942269941730816525'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/01/javascript-clear-webkittransition.html' title='Javascript: Clear a webkitTransition animation'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6441663944171415188</id><published>2011-01-18T19:14:00.000-07:00</published><updated>2011-01-18T19:14:22.804-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='iOS'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><title type='text'>Android: touchmove event bug</title><content type='html'>&lt;b&gt;touchmove&lt;/b&gt; events in Android web browsers have a really serious bug. If you don't include the following code, the &lt;b&gt;touchmove&lt;/b&gt; event will fire once, but not again until you're done moving your touch, which utterly kills the usefulness of the &lt;b&gt;touchmove&lt;/b&gt; event. It's a weird one, and may very well break more advanced touch logic that works on iOS. But if you &lt;b&gt;preventDefault()&lt;/b&gt; on the &lt;b&gt;touchstart&lt;/b&gt; event, your &lt;b&gt;touchmove&lt;/b&gt; will function as expected.&lt;br /&gt;&lt;pre&gt;element.addEventListener( "touchstart", function(e){ onStart(e); }, false );&lt;br /&gt;function onStart ( touchEvent ) {&lt;br /&gt;  if( navigator.userAgent.match(/Android/i) ) {&lt;br /&gt;    touchEvent.preventDefault();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This bug is documented here: &lt;br /&gt;&lt;a href="http://code.google.com/p/android/issues/detail?id=5491"&gt;http://code.google.com/p/android/issues/detail?id=5491&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;and is probably not entirely unrelated to my previous post about weird Android Touch event behavior: &lt;br /&gt;&lt;a href="http://uihacker.blogspot.com/2010/10/android-bug-miss-drag-as-we-are-waiting.html"&gt;http://uihacker.blogspot.com/2010/10/android-bug-miss-drag-as-we-are-waiting.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6441663944171415188?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6441663944171415188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/01/android-touchmove-event-bug.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6441663944171415188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6441663944171415188'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/01/android-touchmove-event-bug.html' title='Android: touchmove event bug'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2204617021462087175</id><published>2011-01-18T00:25:00.000-07:00</published><updated>2011-01-18T00:25:50.217-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='IE'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='chrome'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>CSS Grab hand cursor</title><content type='html'>I wanted a grabby hand cursor in html since we're building sites that have draggable interfaces for both desktop browsers and touchscreen devices. I found some CSS that takes care of most modern browsers, and came up with a little extra for Internet Explorer and Chrome.&lt;br /&gt;&lt;br /&gt;Here's the CSS:&lt;br /&gt;&lt;pre&gt;#trackbar {&lt;br /&gt;  width:100%;&lt;br /&gt;  height:50px;&lt;br /&gt;  cursor:hand;&lt;br /&gt;  cursor:grab;&lt;br /&gt;  cursor:-moz-grab;&lt;br /&gt;  cursor:-webkit-grab;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#trackbar.custom_cursor {&lt;br /&gt;  cursor: url(&lt;a href="https://mail.google.com/mail/images/2/openhand.cur"&gt;https://mail.google.com/mail/images/2/openhand.cur&lt;/a&gt;), default !important;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#trackbar.grabbing {&lt;br /&gt;  cursor:grabbing;&lt;br /&gt;  cursor:-moz-grabbing;&lt;br /&gt;  cursor:-webkit-grabbing;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#trackbar.custom_cursor.grabbing {&lt;br /&gt;  cursor: url(&lt;a href="https://mail.google.com/mail/images/2/closedhand.cur"&gt;https://mail.google.com/mail/images/2/closedhand.cur&lt;/a&gt;), default !important;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The 3 cursor attributes looked great in most modern browsers, but didn't work in IE (obviously) or Chrome. I looked at some code in Google Maps and gleaned the custom cursors, which you can pull down locally, but you have to reference the .cur files absolutely, or they won't work in IE. Awesome. So, because we'd rather use CSS, we only apply the custom cursor files if you're in IE or Chrome. Something like this:&lt;br /&gt;&lt;pre&gt;if( navigator.userAgent.match(/MSIE/i) || navigator.userAgent.match(/Chrome/i) ) document.getElementById('trackbar').className = 'custom_cursor';&lt;br /&gt;&lt;/pre&gt;I'm not sure if there's any way around it, but it doesn't seem like IE will change cursors after you mouse down. So if you add the "grabbing" class on a mousedown event, IE will block your grabby hands :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2204617021462087175?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2204617021462087175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/01/css-grab-hand-cursor.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2204617021462087175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2204617021462087175'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/01/css-grab-hand-cursor.html' title='CSS Grab hand cursor'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6494814086296528762</id><published>2011-01-11T18:50:00.001-07:00</published><updated>2011-01-11T18:53:56.523-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 2'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='textfield'/><category scheme='http://www.blogger.com/atom/ns#' term='as2'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Actionscript: &amp;nbsp; / HTML text issue from an old Flash 8 project</title><content type='html'>I built a project back in 2006 that's amazingly still alive and making lots of money for a client. I had a bit of code that would insert an &lt;b&gt;&amp;amp;nbsp;&lt;/b&gt; into a textfield for dummy spacing in between other letters. Out of nowhere, this stopped working for the client, and all the text was space-less. This is what I had:&lt;br /&gt;&lt;pre&gt;StringUtil.searchReplace( myStr, _dummyChar, '&amp;lt;span class="textDummy"&amp;gt;&amp;amp;nbsp;&amp;lt;/span&amp;gt;' );&lt;br /&gt;&lt;/pre&gt;This now fails to insert a space. I tried just using an actual space, but since this is an html textfield, multiple consecutive spaces don't keep making more room. So, I added a space after the &lt;b&gt;&amp;amp;nbsp;&lt;/b&gt;, and magically, it works like it had in previous years:&lt;br /&gt;&lt;pre&gt;StringUtil.searchReplace( myStr, _dummyChar, '&amp;lt;span class="textDummy"&amp;gt;&amp;amp;nbsp;&amp;lt;/span&amp;gt; ' );&lt;br /&gt;&lt;/pre&gt;Whew fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6494814086296528762?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6494814086296528762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2011/01/actionscript-html-text-issue-from-old.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6494814086296528762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6494814086296528762'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2011/01/actionscript-html-text-issue-from-old.html' title='Actionscript: &amp;amp;nbsp; / HTML text issue from an old Flash 8 project'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-3982458058262245737</id><published>2010-12-08T11:48:00.001-07:00</published><updated>2010-12-08T11:49:53.421-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='scope'/><category scheme='http://www.blogger.com/atom/ns#' term='timer'/><category scheme='http://www.blogger.com/atom/ns#' term='settimeout'/><category scheme='http://www.blogger.com/atom/ns#' term='Prototype.js'/><title type='text'>Javascript: Prototype.js - keep a timer running and maintain scope</title><content type='html'>If you create a Class with the Prototype.js class system, and you want to keep a timer running (for animation or other purposes), use this function to maintain the proper "this" scope:&lt;br /&gt;&lt;pre&gt;runTimer: function() {&lt;br /&gt;    // execute your own code here&lt;br /&gt;&lt;br /&gt;    // keep timer running&lt;br /&gt;    setTimeout(function(t) { &lt;br /&gt;        t.runTimer(); &lt;br /&gt;    }, 1000/30, this);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-3982458058262245737?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/3982458058262245737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/12/javascript-prototypejs-keep-timer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3982458058262245737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3982458058262245737'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/12/javascript-prototypejs-keep-timer.html' title='Javascript: Prototype.js - keep a timer running and maintain scope'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1224378459700572343</id><published>2010-12-01T18:39:00.001-07:00</published><updated>2010-12-01T18:40:44.646-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='Prototype.js'/><title type='text'>Javascript: Prototype.js Class system isolated into one file</title><content type='html'>I wanted to isolate the Class system from Prototype so I could use it with other libraries. I like the way it works, especially the inheritance features. You can copy and paste this into your own class.js file, and use the &lt;a href="http://prototypejs.org/learn/class-inheritance"&gt;Prototype.js class system&lt;/a&gt; just like you would if you had the whole library included in your page. Check it out:&lt;br /&gt;&lt;pre&gt;/* From object.js ------------------------------ */&lt;br /&gt;Object.prototype.getType = function(o) {&lt;br /&gt;  switch(o) {&lt;br /&gt;    case null: return 'Null';&lt;br /&gt;    case (void 0): return 'Undefined';&lt;br /&gt;  }&lt;br /&gt;  var type = typeof o;&lt;br /&gt;  switch(type) {&lt;br /&gt;    case 'boolean': return 'Boolean';&lt;br /&gt;    case 'number':  return 'Number';&lt;br /&gt;    case 'string':  return 'String';&lt;br /&gt;  }&lt;br /&gt;  return 'Object';&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Object.prototype.keys = function(object) {&lt;br /&gt;  if (this.getType(object) !== 'Object') { alert('type error'); }&lt;br /&gt;  var results = [];&lt;br /&gt;  for (var property in object) {&lt;br /&gt;    if (object.hasOwnProperty(property)) {&lt;br /&gt;      results.push(property);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return results;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Object.prototype.isFunction = function(object) {&lt;br /&gt;  return Object.prototype.toString.call(object) === '[object Function]';&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Object.prototype.isUndefined = function(object) {&lt;br /&gt;  return typeof object === &amp;quot;undefined&amp;quot;;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Object.prototype.extend = function(destination, source) {&lt;br /&gt;  for (var property in source)&lt;br /&gt;    destination[property] = source[property];&lt;br /&gt;  return destination;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* From array.js ------------------------------ */&lt;br /&gt;function $A(iterable) {&lt;br /&gt;  if (!iterable) return [];&lt;br /&gt;  // Safari &amp;lt;2.0.4 crashes when accessing property of a node list with property accessor.&lt;br /&gt;  // It nevertheless works fine with `in` operator, which is why we use it here&lt;br /&gt;  if ('toArray' in Object(iterable)) return iterable.toArray();&lt;br /&gt;  var length = iterable.length || 0, results = new Array(length);&lt;br /&gt;  while (length--) results[length] = iterable[length];&lt;br /&gt;  return results;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* From function.js ------------------------------ */&lt;br /&gt;Function.prototype.argumentNames = function() {&lt;br /&gt;  var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]&lt;br /&gt;    .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')&lt;br /&gt;    .replace(/\s+/g, '').split(',');&lt;br /&gt;  return names.length == 1 &amp;amp;&amp;amp; !names[0] ? [] : names;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// patched with inline helpers from function.js&lt;br /&gt;Function.prototype.bind = function(context) {&lt;br /&gt;  if (arguments.length &amp;lt; 2 &amp;amp;&amp;amp; Object.isUndefined(arguments[0])) return this;&lt;br /&gt;  var __method = this, &lt;br /&gt;    args = Array.prototype.slice.call(arguments, 1);&lt;br /&gt;  function update(array, args) {&lt;br /&gt;    var arrayLength = array.length, length = args.length;&lt;br /&gt;    while (length--) array[arrayLength + length] = args[length];&lt;br /&gt;    return array;&lt;br /&gt;  }&lt;br /&gt;  function merge(array, args) {&lt;br /&gt;    array = Array.prototype.slice.call(array, 0);&lt;br /&gt;    return update(array, args);&lt;br /&gt;  }&lt;br /&gt;  return function() {&lt;br /&gt;    var a = merge(args, arguments);&lt;br /&gt;    return __method.apply(context, a);&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// patched with inline helper from function.js&lt;br /&gt;Function.prototype.wrap = function(wrapper) {&lt;br /&gt;  function update(array, args) {&lt;br /&gt;    var arrayLength = array.length, length = args.length;&lt;br /&gt;    while (length--) array[arrayLength + length] = args[length];&lt;br /&gt;    return array;&lt;br /&gt;  }&lt;br /&gt;  var __method = this;&lt;br /&gt;  return function() {&lt;br /&gt;    var a = update([__method.bind(this)], arguments);&lt;br /&gt;    return wrapper.apply(this, a);&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* From class.js ------------------------------ */&lt;br /&gt;/* Based on Alex Arnell's inheritance implementation. */&lt;br /&gt;/* Refer to Prototype's web site for a [tutorial on classes and inheritance (http://prototypejs.org/learn/class-inheritance). */&lt;br /&gt;var Class = (function() {&lt;br /&gt;  &lt;br /&gt;  // Some versions of JScript fail to enumerate over properties, names of which &lt;br /&gt;  // correspond to non-enumerable properties in the prototype chain&lt;br /&gt;  var IS_DONTENUM_BUGGY = (function(){&lt;br /&gt;    for (var p in { toString: 1 }) {&lt;br /&gt;      // check actual property name, so that it works with augmented Object.prototype&lt;br /&gt;      if (p === 'toString') return false;&lt;br /&gt;    }&lt;br /&gt;    return true;&lt;br /&gt;  })();&lt;br /&gt;  &lt;br /&gt;  function subclass() {};&lt;br /&gt;  function create() {&lt;br /&gt;    var parent = null, properties = $A(arguments);&lt;br /&gt;    if (Object.isFunction(properties[0]))&lt;br /&gt;      parent = properties.shift();&lt;br /&gt;&lt;br /&gt;    function klass() {&lt;br /&gt;      this.initialize.apply(this, arguments);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    Object.extend(klass, Class.Methods);&lt;br /&gt;    klass.superclass = parent;&lt;br /&gt;    klass.subclasses = [];&lt;br /&gt;&lt;br /&gt;    if (parent) {&lt;br /&gt;      subclass.prototype = parent.prototype;&lt;br /&gt;      klass.prototype = new subclass;&lt;br /&gt;      parent.subclasses.push(klass);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    for (var i = 0, length = properties.length; i &amp;lt; length; i++)&lt;br /&gt;      klass.addMethods(properties[i]);&lt;br /&gt;&lt;br /&gt;    if (!klass.prototype.initialize)&lt;br /&gt;      klass.prototype.initialize = Prototype.emptyFunction;&lt;br /&gt;&lt;br /&gt;    klass.prototype.constructor = klass;&lt;br /&gt;    return klass;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function addMethods(source) {&lt;br /&gt;    var ancestor   = this.superclass &amp;amp;&amp;amp; this.superclass.prototype,&lt;br /&gt;        properties = Object.keys(source);&lt;br /&gt;&lt;br /&gt;    // IE6 doesn't enumerate `toString` and `valueOf` (among other built-in `Object.prototype`) properties,&lt;br /&gt;    // Force copy if they're not Object.prototype ones.&lt;br /&gt;    // Do not copy other Object.prototype.* for performance reasons&lt;br /&gt;    if (IS_DONTENUM_BUGGY) {&lt;br /&gt;      if (source.toString != Object.prototype.toString)&lt;br /&gt;        properties.push(&amp;quot;toString&amp;quot;);&lt;br /&gt;      if (source.valueOf != Object.prototype.valueOf)&lt;br /&gt;        properties.push(&amp;quot;valueOf&amp;quot;);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    for (var i = 0, length = properties.length; i &amp;lt; length; i++) {&lt;br /&gt;      var property = properties[i], &lt;br /&gt;          value = source[property];&lt;br /&gt;      if (ancestor &amp;amp;&amp;amp; Object.isFunction(value) &amp;amp;&amp;amp;&lt;br /&gt;          value.argumentNames()[0] == &amp;quot;$super&amp;quot;) {&lt;br /&gt;        var method = value;&lt;br /&gt;        value = (function(m) {&lt;br /&gt;          return function() { return ancestor[m].apply(this, arguments); };&lt;br /&gt;        })(property).wrap(method);&lt;br /&gt;&lt;br /&gt;        value.valueOf = method.valueOf.bind(method);&lt;br /&gt;        value.toString = method.toString.bind(method);&lt;br /&gt;      }&lt;br /&gt;      this.prototype[property] = value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return this;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return {&lt;br /&gt;    create: create,&lt;br /&gt;    Methods: {&lt;br /&gt;      addMethods: addMethods&lt;br /&gt;    }&lt;br /&gt;  };&lt;br /&gt;})();&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1224378459700572343?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1224378459700572343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/12/javascript-prototypejs-class-system.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1224378459700572343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1224378459700572343'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/12/javascript-prototypejs-class-system.html' title='Javascript: Prototype.js Class system isolated into one file'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-8239951904208131768</id><published>2010-11-30T17:58:00.000-07:00</published><updated>2010-11-30T17:58:17.064-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video'/><category scheme='http://www.blogger.com/atom/ns#' term='m4v'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='Phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Android: Phonegap issue with HTML5 video</title><content type='html'>We've been trying to implement HTML5 video inside a WebView in an Android Phonegap app, and there's a big difference between the embedded web browser and the native web browser on the Samsung Galaxy Tab (and likely other Android devices). In the native browser, an HTML5 &amp;lt;video&amp;gt; player will pop the video into the native media player, and should play fine if you've used an appropriate codec, and jumped through the right hoops. But, in an embedded browser in a Phonegap app, the video won't play at all. We resorted to using an &amp;lt;a&amp;gt; link with a _blank target to pop you completely out of the app. This was the only solution we could come up with. It's a pretty sad story dealing with the "standards" of HTML5 video across all the platforms and browsers that supposedly support it. I'm not sure there's a good way to deal with all of the different platforms/scenarios...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-8239951904208131768?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/8239951904208131768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/11/android-phonegap-issue-with-html5-video.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8239951904208131768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8239951904208131768'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/11/android-phonegap-issue-with-html5-video.html' title='Android: Phonegap issue with HTML5 video'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5841759139997639445</id><published>2010-11-29T17:35:00.003-07:00</published><updated>2010-11-30T10:36:29.110-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='processing.org'/><category scheme='http://www.blogger.com/atom/ns#' term='generative art'/><category scheme='http://www.blogger.com/atom/ns#' term='drawing'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='processing'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Javascript: red plasma experiment</title><content type='html'>I ported an old Processing experiment of mine today, as an exercise to get myself back into coding after a couple weeks of vacation. Copy and paste the code into your own html file to try it out:&lt;br /&gt;&lt;pre&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;  &amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Plasma&amp;lt;/title&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;        function initPlasma()&lt;br /&gt;        {&lt;br /&gt;            /* MATH FUNCTIONS ------------------------------ */&lt;br /&gt;            &lt;br /&gt;            function MathUtil() {}&lt;br /&gt;&lt;br /&gt;            MathUtil.getDistance = function ( a, b ) {&lt;br /&gt;                return Math.abs( Math.sqrt(a*a + b*b) );&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            MathUtil.randRangeDecimel = function ( min, max ) {  &lt;br /&gt;                return Math.random() * ( max - min ) + min;&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            /* GRID CELL CLASS ------------------------------ */&lt;br /&gt;            &lt;br /&gt;            var Cell = function( x, y, w, h ) {&lt;br /&gt;                this.x = x;&lt;br /&gt;                this.y = y;&lt;br /&gt;                this.w = w;&lt;br /&gt;                this.h = h;&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            Cell.prototype.update = function( r, g, b ) {&lt;br /&gt;                this.r = r;&lt;br /&gt;                this.g = g;&lt;br /&gt;                this.b = b;&lt;br /&gt;                                &lt;br /&gt;                this.draw();&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            Cell.prototype.draw = function() {&lt;br /&gt;                if( !plasma ) return;&lt;br /&gt;                &lt;br /&gt;                // get color, based on distance &lt;br /&gt;                var ctrlPt1 = MathUtil.getDistance( this.x - plasma.controlPoints[0].x, this.y - plasma.controlPoints[0].y );&lt;br /&gt;                var ctrlPt2 = MathUtil.getDistance( this.x - plasma.controlPoints[1].x, this.y - plasma.controlPoints[1].y );&lt;br /&gt;                var ctrlPt3 = MathUtil.getDistance( this.x - plasma.controlPoints[2].x, this.y - plasma.controlPoints[2].y );&lt;br /&gt;                &lt;br /&gt;                var rVal = .5+.5*Math.sin(this.r) * Math.cos(ctrlPt1/100) * Math.cos(ctrlPt2/100) * Math.sin(ctrlPt3/100);&lt;br /&gt;                var gVal = .2+.5*Math.sin(this.g) * Math.sin(ctrlPt1/100) * Math.sin(ctrlPt2/100) * Math.sin(ctrlPt3/100);&lt;br /&gt;                var bVal = .2+.5*Math.cos(this.b) * Math.sin(ctrlPt1/100) * Math.cos(ctrlPt2/100) * Math.sin(ctrlPt3/100)&lt;br /&gt;                &lt;br /&gt;                // draw pixel to canvas&lt;br /&gt;                plasma.context.fillStyle = &amp;quot;rgb(&amp;quot;+ Math.round( 127 + rVal * 255 ) +&amp;quot;,&amp;quot;+ Math.round( 127 + gVal * 255 ) +&amp;quot;,&amp;quot;+ Math.round( 127 + bVal * 255 ) +&amp;quot;)&amp;quot;; &lt;br /&gt;                plasma.context.fillRect ( this.x, this.y, this.w, this.h );  &lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            &lt;br /&gt;            /* CONTROL POINT CLASS ------------------------------ */&lt;br /&gt;            &lt;br /&gt;            var ControlPoint = function( canvasW, canvasH ) {&lt;br /&gt;                // create random x,y starting point &lt;br /&gt;                this.incX = MathUtil.randRangeDecimel( 0, 2 * Math.PI );&lt;br /&gt;                this.incY = MathUtil.randRangeDecimel( 0, 2 * Math.PI );&lt;br /&gt;                // create random x,y oscillating speed &lt;br /&gt;                this.incXSpeed = MathUtil.randRangeDecimel( .01, .1 );&lt;br /&gt;                this.incYSpeed = MathUtil.randRangeDecimel( .01, .1 );&lt;br /&gt;                // store center point to oscillate around&lt;br /&gt;                this.centerX = canvasW / 2;&lt;br /&gt;                this.centerY = canvasH / 2;&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            ControlPoint.prototype.update = function() {&lt;br /&gt;                // increment oscillating based on randomly-calculated speed&lt;br /&gt;                this.incX += this.incXSpeed;&lt;br /&gt;                this.incY += this.incYSpeed;&lt;br /&gt;                // update coordinate&lt;br /&gt;                this.x = this.centerX + this.centerX * Math.sin( this.incX );&lt;br /&gt;                this.y = this.centerY + this.centerY * Math.sin( this.incY );&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            &lt;br /&gt;            /* PLASMA CLASS ------------------------------ */&lt;br /&gt;            &lt;br /&gt;            var Plasma = function() {&lt;br /&gt;                this.COLS = 50;&lt;br /&gt;                this.ROWS = 50;&lt;br /&gt;                this.CANVAS_W = 500;&lt;br /&gt;                this.CANVAS_H = 500;&lt;br /&gt;                this.FPS = 1000/30;&lt;br /&gt;                this.NUM_CONTROL_POINTS = 3;&lt;br /&gt;                &lt;br /&gt;                this.startR = MathUtil.randRangeDecimel(0,2*Math.PI);&lt;br /&gt;                this.startG = MathUtil.randRangeDecimel(0,2*Math.PI);&lt;br /&gt;                this.startB = MathUtil.randRangeDecimel(0,2*Math.PI);&lt;br /&gt;                this.startIncR = MathUtil.randRangeDecimel(.001,.05);&lt;br /&gt;                this.startIncG = MathUtil.randRangeDecimel(.001,.05);&lt;br /&gt;                this.startIncB = MathUtil.randRangeDecimel(.001,.05);&lt;br /&gt;                this.incR = MathUtil.randRangeDecimel(.0001,.001);&lt;br /&gt;                this.incG = MathUtil.randRangeDecimel(.0001,.001);&lt;br /&gt;                this.incB = MathUtil.randRangeDecimel(.0001,.001);&lt;br /&gt;                &lt;br /&gt;                this.canvas;&lt;br /&gt;                this.context;&lt;br /&gt;                this.grid;&lt;br /&gt;                &lt;br /&gt;                this.buildStage();&lt;br /&gt;                this.createGrid();&lt;br /&gt;                this.createControlPoints();&lt;br /&gt;                this.addSaveFunctionality();&lt;br /&gt;                &lt;br /&gt;                var self = this;&lt;br /&gt;                setInterval( function(){ self.update(); }, this.FPS );&lt;br /&gt;            };&lt;br /&gt;        &lt;br /&gt;            Plasma.prototype.buildStage = function() {&lt;br /&gt;                // create and attach canvas element&lt;br /&gt;                this.canvas = document.createElement('canvas');&lt;br /&gt;                this.canvas.width = this.CANVAS_W;&lt;br /&gt;                this.canvas.height = this.CANVAS_H;&lt;br /&gt;                document.body.appendChild( this.canvas );&lt;br /&gt;                &lt;br /&gt;                // store graphical context&lt;br /&gt;                this.context = this.canvas.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            Plasma.prototype.createGrid = function() {&lt;br /&gt;                // calculate &amp;quot;pixel&amp;quot; size&lt;br /&gt;                var boxW = this.CANVAS_W / this.COLS;&lt;br /&gt;                var boxH = this.CANVAS_H / this.ROWS;&lt;br /&gt;                &lt;br /&gt;                // create 2D array of grid cells&lt;br /&gt;                this.grid = new Array( this.COLS );&lt;br /&gt;                for( var i = 0; i &amp;lt; this.COLS; i++ ) {&lt;br /&gt;                    this.grid[ i ] = new Array( this.ROWS )&lt;br /&gt;                    for( var j = 0; j &amp;lt; this.ROWS; j++ ) {&lt;br /&gt;                        this.grid[ i ][ j ] = new Cell( i * boxW, j * boxH, boxW, boxH );&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            Plasma.prototype.createControlPoints = function() {&lt;br /&gt;                this.controlPoints = [];&lt;br /&gt;                for ( var i = 0; i &amp;lt; this.NUM_CONTROL_POINTS; i++ ) {&lt;br /&gt;                    this.controlPoints.push( new ControlPoint( this.CANVAS_W, this.CANVAS_H ) );&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            Plasma.prototype.addSaveFunctionality = function() {&lt;br /&gt;                var self = this;&lt;br /&gt;                this.canvas.addEventListener(&amp;quot;click&amp;quot;, function(e) { &lt;br /&gt;                    window.open( self.canvas.toDataURL(&amp;quot;image/jpeg&amp;quot;) ); &lt;br /&gt;                }, false);&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            Plasma.prototype.update = function() {&lt;br /&gt;                &lt;br /&gt;                // increment the starting colors&lt;br /&gt;                this.startR += this.startIncR;&lt;br /&gt;                var curR = this.startR;&lt;br /&gt;                this.startG += this.startIncG;&lt;br /&gt;                var curG = this.startG;&lt;br /&gt;                this.startB += this.startIncB;&lt;br /&gt;                var curB = this.startB;&lt;br /&gt;                &lt;br /&gt;                // update control points&lt;br /&gt;                for ( var i = 0; i &amp;lt; this.NUM_CONTROL_POINTS; i++ ) {&lt;br /&gt;                    this.controlPoints[i].update();&lt;br /&gt;                }&lt;br /&gt;                &lt;br /&gt;                // increment grid cells and draw to canvas&lt;br /&gt;                for (var i = 0; i &amp;lt; this.COLS; i++) {&lt;br /&gt;                    for (var j = 0; j &amp;lt; this.ROWS; j++) {&lt;br /&gt;                        // send new base color to cells&lt;br /&gt;                        this.grid[i][j].update( curR, curG, curB );&lt;br /&gt;                        &lt;br /&gt;                        // increment color as we traverse the grid&lt;br /&gt;                        curR += this.incR;&lt;br /&gt;                        curG += this.incG * 3;&lt;br /&gt;                        curB += this.incB;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            &lt;br /&gt;            // kick off the plasma controller&lt;br /&gt;            var plasma = new Plasma();     &lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;        &lt;br /&gt;    &amp;lt;style&amp;gt;&lt;br /&gt;        body, html {&lt;br /&gt;            background-color:black;&lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/style&amp;gt;&lt;br /&gt;  &amp;lt;/head&amp;gt;&lt;br /&gt;  &amp;lt;body onload=&amp;quot;initPlasma();&amp;quot;&amp;gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And the result:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_EjN6eQMIZW4/TPRGr6IVe2I/AAAAAAAAABI/t56pXWhYMMU/s1600/plasma.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="319" src="http://3.bp.blogspot.com/_EjN6eQMIZW4/TPRGr6IVe2I/AAAAAAAAABI/t56pXWhYMMU/s320/plasma.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5841759139997639445?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5841759139997639445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/11/javascript-red-plasma-experiment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5841759139997639445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5841759139997639445'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/11/javascript-red-plasma-experiment.html' title='Javascript: red plasma experiment'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_EjN6eQMIZW4/TPRGr6IVe2I/AAAAAAAAABI/t56pXWhYMMU/s72-c/plasma.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-599454143954781977</id><published>2010-11-04T18:00:00.001-06:00</published><updated>2010-11-04T18:00:55.619-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='Prototype.js'/><title type='text'>Android: Phonegap 0.9.2 doesn't work with Prototype.js 1.6.1</title><content type='html'>This morning I upgraded to Phonegap 0.9.2 on an HTML-based native app for Android, in order to use the new notification.confirm() function. After moving my project to this new version, I started getting this error:&lt;br /&gt;&lt;pre&gt;Error initializing PhoneGap: JSON error&lt;br /&gt;&lt;/pre&gt;I was using Prototype.js 1.6.1, and after a bunch of investigation, I determined that it was Prototype that was causing the error. I replaced 1.6.1 with 1.7_rc3, and magically, everything works. I looked into why this might be happening, but decided to move on with my life and just go with 1.7_rc3 :) &lt;br /&gt;&lt;br /&gt;Hopefully this post saves someone a little madness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-599454143954781977?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/599454143954781977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/11/android-phonegap-092-doesnt-work-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/599454143954781977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/599454143954781977'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/11/android-phonegap-092-doesnt-work-with.html' title='Android: Phonegap 0.9.2 doesn&apos;t work with Prototype.js 1.6.1'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-30467508271847945</id><published>2010-10-29T11:01:00.002-06:00</published><updated>2010-11-08T17:01:20.121-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='Phonegap'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Android bug: "Miss a drag as we are waiting for WebCore's response for touch down."</title><content type='html'>I'm using &lt;a href="http://www.phonegap.com/"&gt;Phonegap&lt;/a&gt; to port an HTML5 iPad app over to the Android platform. On my development HTC Incredible phone, every time I swipe my finger far enough, my app would freeze, and the adb debugging console would give me this error: "Miss a drag as we are waiting for WebCore's response for touch down." I researched a bunch and didn't find any solutions. I did find the Java code that logs this error in the core Android &lt;a href="http://www.netmite.com/android/mydroid/2.0/frameworks/base/core/java/android/webkit/WebView.java"&gt;WebView.java&lt;/a&gt; class, but it didn't give me any clues to fix it.&lt;br /&gt;&lt;br /&gt;I searched and hacked, and removed all my touch event listening code, and it would still break. Luckily the company work for has the resources to invest in development, and we went out and got a Samsung Galaxy S phone. I set the device up, published the app, and this phone did not have the cryptic issue! It did, however, show a range of other issues with fonts and the &amp;lt;canvas&amp;gt; object, which made me sad, as it's clear that building an HTML5-based app for Android isn't as easy as I hoped. The fragmentation of the Android platform is definitely an issue if you're attempting complex UI design and interaction with HTML/Javascript. I recommend keeping your HTML5 app very simple if you're targeting multiple Android platforms. Even though all new Android devices use Webkit, there are plenty of small, ugly differences.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[UPDATE]&lt;/b&gt;: The following code, when removed from my project, got rid of this weird error:&lt;br /&gt;&lt;pre&gt;document.ontouchmove = function(event) {&lt;br /&gt;    event.preventDefault();&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Another update... Check out this post, and try out the demo code to get a bit more idea about how to handle preventDefault() on touch events in the Android browser: &lt;a href="http://code.google.com/p/android/issues/detail?id=4549"&gt;http://code.google.com/p/android/issues/detail?id=4549&lt;/a&gt;. It still crashes on my HTC device, but works great on the Samsung device.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-30467508271847945?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/30467508271847945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/10/android-bug-miss-drag-as-we-are-waiting.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/30467508271847945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/30467508271847945'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/10/android-bug-miss-drag-as-we-are-waiting.html' title='Android bug: &quot;Miss a drag as we are waiting for WebCore&apos;s response for touch down.&quot;'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-384435925107670850</id><published>2010-10-22T11:44:00.002-06:00</published><updated>2010-10-29T14:58:16.852-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='click'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Android browser bug: -webkit-transform scaling discrepency</title><content type='html'>&lt;b&gt;[UPDATE]: this only happens on my HTC Incredible device, but not my Samsung Galaxy S device. yeesh.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I'm porting an HTML5 app we built for the iPad over to Android for the upcoming Samsung tablet. With the small difference in aspect ratio, I'm scaling down the entire site to avoid rebuilding everything. It turns out, that if you scale a container with CSS like so: &lt;br /&gt;&lt;pre&gt;-webkit-transform-origin: 0 0;&lt;br /&gt;-webkit-transform : scale(0.78125);&lt;br /&gt;&lt;/pre&gt;That works fine. However, I wanted to scale it dynamically with javascript, based on the device size, like so: &lt;br /&gt;&lt;pre&gt;var globalScale = window.innerWidth / 768;&lt;br /&gt;element.style.webkitTransformOrigin = '0 0';&lt;br /&gt;element.style.webkitTransform = 'scale(' + globalScale + ')';&lt;br /&gt;&lt;/pre&gt;The result looks the same, but now clicking on anything in the scaled container is completely broken. :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-384435925107670850?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/384435925107670850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/10/android-browser-bug-webkit-transform.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/384435925107670850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/384435925107670850'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/10/android-browser-bug-webkit-transform.html' title='Android browser bug: -webkit-transform scaling discrepency'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-3040906253287039399</id><published>2010-09-14T17:31:00.001-06:00</published><updated>2010-09-14T17:32:56.765-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Javascript: strip HTML tags from a string</title><content type='html'>Here's a super simple RegEx to use when you want to be sure all html tags are removed from a string.&lt;br /&gt;&lt;pre&gt;theString.replace(/&lt;.*?&gt;/g, '');&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-3040906253287039399?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/3040906253287039399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/09/javascript-strip-html-tags-from-string.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3040906253287039399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3040906253287039399'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/09/javascript-strip-html-tags-from-string.html' title='Javascript: strip HTML tags from a string'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-8369807378476404082</id><published>2010-09-10T16:50:00.001-06:00</published><updated>2010-09-10T16:53:34.511-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='rotate'/><category scheme='http://www.blogger.com/atom/ns#' term='detection'/><category scheme='http://www.blogger.com/atom/ns#' term='animate'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='style'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>HTML/CSS on Android: rotation CSS difference between Android 2.1 and 2.2</title><content type='html'>Well, the splinternet is getting more interesting. As many developers settle on html as the most cross-functional platform, we're faced with ever more browsers and small differences between them. One that I just found is a difference in CSS positioning and rotation between the browsers on Android 2.1 and Android 2.2. &lt;br /&gt;&lt;br /&gt;On my current project, I have a fancy UI that has an element constantly changing rotation and position using webkit transform CSS built with javascript. On Android 2.1, it worked fine as a 1-liner: &lt;br /&gt;&lt;pre&gt;element.style.webkitTransform = "translate3d(" + xPos + "px, " + yPos + "px, 0px) rotate(" + rotation + "deg)";&lt;br /&gt;&lt;/pre&gt;But, on Android 2.2, the rotation stopped working. It seems that you can't have the &lt;b&gt;translate3d&lt;/b&gt; &lt;em&gt;and&lt;/em&gt; the &lt;b&gt;rotate&lt;/b&gt; properties all set in the style.webkitTransform property. To fix the issue, I positioned using traditional absolute coordinates with the &lt;b&gt;top&lt;/b&gt; and &lt;b&gt;left&lt;/b&gt; CSS properties, and then used the webkitTransform property to do the rotation. There were a ton of special browser cases in my project to handle different things. Check out my platform detection class below to see how I handled a lot of special cases in one place.&lt;br /&gt;&lt;pre&gt;PlatformHelper = function ()&lt;br /&gt;{&lt;br /&gt;    this.webkit_css_enabled = false;&lt;br /&gt;    this.animations_enabled = false;&lt;br /&gt;    this.is_android = false;&lt;br /&gt;    this.is_android21 = false;&lt;br /&gt;    this.is_android22 = false;&lt;br /&gt;    this.is_idevice = false;&lt;br /&gt;    this.is_touchscreen = false;&lt;br /&gt;    this.is_msie = false;&lt;br /&gt;    this.is_msie6 = false;&lt;br /&gt;    this.is_msie8 = false;&lt;br /&gt;    this.is_firefox = false;&lt;br /&gt;    return this;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;PlatformHelper.prototype.init = function ()&lt;br /&gt;{&lt;br /&gt;    // check for webkit positioning capability&lt;br /&gt;    if( navigator.userAgent.match(/iPhone/i) ) this.webkit_css_enabled = true;&lt;br /&gt;    else if( navigator.userAgent.match(/iPod/i) ) this.webkit_css_enabled = true;&lt;br /&gt;    else if( navigator.userAgent.match(/iPad/i) ) this.webkit_css_enabled = true;&lt;br /&gt;    else if( navigator.userAgent.match(/Chrome/i) ) this.webkit_css_enabled = true;&lt;br /&gt;    else if( navigator.userAgent.match(/Safari/i) ) this.webkit_css_enabled = true;&lt;br /&gt;    &lt;br /&gt;    // check for certain platforms&lt;br /&gt;    if( navigator.userAgent.match(/Android/i) ) this.is_android = true;&lt;br /&gt;    if( navigator.userAgent.match(/Android 2.1/i) ) this.is_android21 = true;&lt;br /&gt;    if( navigator.userAgent.match(/Android 2.2/i) ) this.is_android22 = true;&lt;br /&gt;    if( navigator.userAgent.match(/MSIE/i) ) this.is_msie = true;&lt;br /&gt;    if( navigator.userAgent.match(/MSIE 6/i) ) this.is_msie6 = true;&lt;br /&gt;    if( navigator.userAgent.match(/MSIE 8/i) ) this.is_msie8 = true;&lt;br /&gt;    if( navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i) ) this.is_idevice = true;&lt;br /&gt;    if( navigator.userAgent.match(/Firefox/i) ) this.is_firefox = true;&lt;br /&gt;    &lt;br /&gt;    // special cases for touchscreens&lt;br /&gt;    if( this.is_android == true || this.is_idevice == true ) this.is_touchscreen = true;&lt;br /&gt;    &lt;br /&gt;    // decide who sees animations&lt;br /&gt;    if( this.is_msie == true ) this.animations_enabled = false;&lt;br /&gt;    else this.animations_enabled = true;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;PlatformHelper.prototype.updatePosition = function ( element, xPos, yPos, rotation )&lt;br /&gt;{&lt;br /&gt;    if( !this.webkit_css_enabled || this.is_android22 )&lt;br /&gt;    {&lt;br /&gt;        element.style.left = xPos + 'px';&lt;br /&gt;        element.style.top = yPos + 'px';&lt;br /&gt;        element.style.MozTransform = 'rotate(' + rotation + 'deg)';&lt;br /&gt;        element.style.webkitTransform = 'rotate(' + rotation + 'deg)';&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        var new_transform = "translate3d(" + xPos + "px, " + yPos + "px, 0px) rotate(" + rotation + "deg)";&lt;br /&gt;        if( element.style.webkitTransform != new_transform )    // only apply style if not already in position&lt;br /&gt;         element.style.webkitTransform = new_transform;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-8369807378476404082?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/8369807378476404082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/09/htmlcss-on-android-rotation-css.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8369807378476404082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8369807378476404082'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/09/htmlcss-on-android-rotation-css.html' title='HTML/CSS on Android: rotation CSS difference between Android 2.1 and 2.2'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-4808245896099935343</id><published>2010-09-08T17:03:00.001-06:00</published><updated>2010-09-08T20:25:11.101-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='setinterval'/><category scheme='http://www.blogger.com/atom/ns#' term='textual'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='animate'/><category scheme='http://www.blogger.com/atom/ns#' term='drawing'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Javascript / CSS animated text fire effect</title><content type='html'>A coworker sent me a &lt;a href="http://www.css3.info/preview/text-shadow/" target="_blank"&gt;funny example&lt;/a&gt; of a &lt;b&gt;text-shadow&lt;/b&gt; CSS fire effect. I had a little time to kill, so I took the example and created an animated version using javascript. It's not very realistic, but it is highly silly:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_EjN6eQMIZW4/TIhFIF-3E1I/AAAAAAAAABA/nUy_y8E-8do/s1600/cssFire.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_EjN6eQMIZW4/TIhFIF-3E1I/AAAAAAAAABA/nUy_y8E-8do/s320/cssFire.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Copy and paste the code into an html file to try it out:&lt;br /&gt;&lt;pre&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;  &amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Fire&amp;lt;/title&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;        function fireText()&lt;br /&gt;        {&lt;br /&gt;            var FireColorStop = function( xPos, yPos, blur, color )&lt;br /&gt;            {&lt;br /&gt;                this.x = xPos;&lt;br /&gt;                this.y = yPos;&lt;br /&gt;                this.blur = blur;&lt;br /&gt;                this.color = color;&lt;br /&gt;                this.oscSpeed = Math.random() * Math.abs( yPos ) / 75;&lt;br /&gt;                this.oscIncrement = 0;&lt;br /&gt;                this.xOffset = 0;&lt;br /&gt;                this.yOffset = 0;&lt;br /&gt;                this.blurOffset = 0;&lt;br /&gt;            };&lt;br /&gt;        &lt;br /&gt;            FireColorStop.prototype.oscillate = function() &lt;br /&gt;            {&lt;br /&gt;                this.oscIncrement += this.oscSpeed;&lt;br /&gt;                this.xOffset = Math.sin(this.oscIncrement) * this.blur / 3;&lt;br /&gt;                this.yOffset = Math.sin(this.oscIncrement) * 1;&lt;br /&gt;                this.blurOsc = this.blur + 10 + Math.sin(this.oscIncrement) * 3;&lt;br /&gt;            };&lt;br /&gt;        &lt;br /&gt;            FireColorStop.prototype.getCSS = function() &lt;br /&gt;            {&lt;br /&gt;                return ( this.x + this.xOffset ) + 'px ' + ( this.y + this.yOffset ) + 'px ' + this.blurOsc + 'px ' + this.color; &lt;br /&gt;            };&lt;br /&gt;            &lt;br /&gt;            // create objects for each color stop for independent animation&lt;br /&gt;            var fireColors = [  new FireColorStop(0,  0,  4,  '#FFFFFF'),&lt;br /&gt;                                new FireColorStop(0, -5,  4,  '#FFFF33'),&lt;br /&gt;                                new FireColorStop(2, -10, 6,  '#FFDD33'),&lt;br /&gt;                                new FireColorStop(-2,-15, 11, '#FF8800'),&lt;br /&gt;                                new FireColorStop(2, -25, 18, '#FF2200')&lt;br /&gt;                                ];&lt;br /&gt;        &lt;br /&gt;            var fps = 1000/30;&lt;br /&gt;            var text = document.getElementById('fireText');&lt;br /&gt;            &lt;br /&gt;            // oscillate color stops and rebuild fire css&lt;br /&gt;            setInterval( function(){ &lt;br /&gt;                var shadowCSS = '';&lt;br /&gt;                for( var i = 0; i &amp;lt; fireColors.length; i++ )&lt;br /&gt;                {&lt;br /&gt;                    fireColors[i].oscillate();&lt;br /&gt;                &lt;br /&gt;                    shadowCSS += fireColors[i].getCSS();&lt;br /&gt;                    if( i &amp;lt; fireColors.length - 1 )&lt;br /&gt;                        shadowCSS += ', ';&lt;br /&gt;                }&lt;br /&gt;                text.style.textShadow = shadowCSS;&lt;br /&gt;            }, fps );&lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;        &lt;br /&gt;    &amp;lt;style&amp;gt;&lt;br /&gt;        body, html {&lt;br /&gt;            background-color:black;&lt;br /&gt;        }&lt;br /&gt;        #fireText {&lt;br /&gt;            background-color:black;&lt;br /&gt;            position:absolute;&lt;br /&gt;            display:block;&lt;br /&gt;            width:100%;&lt;br /&gt;            height:300px;&lt;br /&gt;            line-height:300px;&lt;br /&gt;            color:white;&lt;br /&gt;            font-family: Arial, Verdana, sans-serif;&lt;br /&gt;            font-size:50px;&lt;br /&gt;            font-weight:bold;&lt;br /&gt;            text-align:center;&lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/style&amp;gt;&lt;br /&gt;    &lt;br /&gt;  &amp;lt;/head&amp;gt;&lt;br /&gt;  &amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;div id="fireText"&amp;gt;&lt;br /&gt;        Yeah Dude.&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;        fireText();&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;  &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-4808245896099935343?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/4808245896099935343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/09/javascript-css-animated-text-fire.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4808245896099935343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4808245896099935343'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/09/javascript-css-animated-text-fire.html' title='Javascript / CSS animated text fire effect'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_EjN6eQMIZW4/TIhFIF-3E1I/AAAAAAAAABA/nUy_y8E-8do/s72-c/cssFire.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2546197853871163258</id><published>2010-07-27T16:48:00.001-06:00</published><updated>2010-07-27T16:51:20.867-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='setinterval'/><category scheme='http://www.blogger.com/atom/ns#' term='pinch'/><category scheme='http://www.blogger.com/atom/ns#' term='zoom'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='settimeout'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Android browser bug: pinch/zoom kills setTimeout()</title><content type='html'>I'm working on some cross-platform/mobile touch/mouse code for a fancy html/js UI, and everything's been working great, but when I pinch/zoom the web page in an Android browser, my setTimeout() calls stop running. To be safe, I recommend using setInterval() instead.&lt;br /&gt;&lt;pre&gt;// before:&lt;br /&gt;setTimeout( function() { runTimer(); } , 1000/30 );&lt;br /&gt;function runTimer() {&lt;br /&gt;    // update graphics here&lt;br /&gt;    setTimeout( function() { runTimer(); } , 1000/30 );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// after:&lt;br /&gt;setInterval( function(){ runTimer(); }, 1000/30 );&lt;br /&gt;function runTimer() {&lt;br /&gt;    // update graphics here&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I initially thought that my touch events (touchstart, touchmove, touchend) were randomly failing after zooming, because my custom motion code would completely break after running at a solid 30+ fps. It appears that this is a known bug in pre-2.2 (Froyo) Android web browsers: &lt;a href="http://code.google.com/p/android/issues/detail?id=8566" target="_blank"&gt;http://code.google.com/p/android/issues/detail?id=8566&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2546197853871163258?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2546197853871163258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/07/android-browser-bug-pinchzoom-kills.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2546197853871163258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2546197853871163258'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/07/android-browser-bug-pinchzoom-kills.html' title='Android browser bug: pinch/zoom kills setTimeout()'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1955388161329345023</id><published>2010-07-25T15:51:00.000-06:00</published><updated>2010-07-25T15:51:05.718-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='images'/><category scheme='http://www.blogger.com/atom/ns#' term='flickr'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>PHPFlicker: Get images by user's tag</title><content type='html'>I started using phpFlickr (&lt;a href="http://phpflickr.com/" target="_blank"&gt;http://phpflickr.com/&lt;/a&gt;), so I could use Flickr as a query-able backend for some of my images. I'm tagging images that I want to show up on certain pages of my site, but there wasn't an example for using tags on the phpFlickr examples page. So here's an example:&lt;br /&gt;&lt;pre&gt;&amp;lt;?php&lt;br /&gt; $api_key = "YOUR_API_KEY";&lt;br /&gt; $user_id = "YOUR_USER_ID";&lt;br /&gt; $secret = "YOUR_SECRET";&lt;br /&gt; &lt;br /&gt; require_once("./php/flickr/phpFlickr.php");&lt;br /&gt; $f = new phpFlickr($api_key, $secret);&lt;br /&gt;&lt;br /&gt; $photos = $f-&gt;photos_search(array( "api_key"=&gt;$api_key, "user_id"=&gt;$user_id, "tags"=&gt;"promo", "tag_mode"=&gt;"any", "extras"=&gt;"original_format,tags,url_o,description") );&lt;br /&gt; &lt;br /&gt; // Loop through the photos and output the html&lt;br /&gt; foreach( (array)$photos['photo'] as $photo ) &lt;br /&gt; {&lt;br /&gt;  // get original, or large if no original&lt;br /&gt;  if( isset( $photo['url_o'] ) ) &lt;br /&gt;   echo '&amp;lt;a rel="lightbox[flickr]" title="'. $photo['title'].' - '. $photo['description'].'" href="'. $photo['url_o'] .'"&gt;';&lt;br /&gt;  else&lt;br /&gt;   echo '&amp;lt;a rel="lightbox[flickr]" title="'. $photo['title'].' - '. $photo['description'].'" href="'. $f-&gt;buildPhotoURL($photo, "large") .'"&gt;';&lt;br /&gt;&lt;br /&gt;  echo '&amp;lt;img border="0" alt="'.$photo[title].' - '. $photo['description'].'" title="'.$photo[title].' - '. $photo['description'].'" src="' . $f-&gt;buildPhotoURL($photo, "square") . '" /&gt;';&lt;br /&gt;&lt;br /&gt;  echo "&amp;lt;/a&gt;";&lt;br /&gt; }&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Just replace YOUR_API_KEY, YOUR_USER_ID (something like: 38845956@N05), and YOUR_SECRET (something like 7fc67607bd5abc59). This type of search is "secure", meaning that you have to acquire a secret key via the &lt;a href="http://www.flickr.com/services/api/" target="_blank"&gt;Flickr API&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This script will display square thumbnails that link out to the largest available image size. This can easily by styled, augmented with a lightbox javascript, or customized via the phpFlickr search options. &lt;br /&gt;&lt;br /&gt;Enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1955388161329345023?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1955388161329345023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/07/phpflicker-get-images-by-users-tag.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1955388161329345023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1955388161329345023'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/07/phpflicker-get-images-by-users-tag.html' title='PHPFlicker: Get images by user&apos;s tag'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5687261998410304273</id><published>2010-07-05T01:31:00.002-06:00</published><updated>2010-07-05T01:33:20.764-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><title type='text'>Javascript: iPad orientation class with Prototype.js</title><content type='html'>I'm writing an iPad app in "HTML5", and I wanted to keep track of the device orientation. I wrote this little class to send notifications when it changes, and to always have simple access to the current state. This requires &lt;a href="http://www.prototypejs.org" target="_blank"&gt;Prototype.js&lt;/a&gt;, but could easily be ported to another OOP style.&lt;br /&gt;&lt;pre&gt;var AppState = Class.create({&lt;br /&gt; PORTRAIT: 0,&lt;br /&gt; LANDSCAPE: 1,&lt;br /&gt; orientation: -1,    &lt;br /&gt; initialize: function() {&lt;br /&gt;  this.orientation = this.PORTRAIT; // default for desktop browser&lt;br /&gt;  this.setUpOrientationListener();&lt;br /&gt; },&lt;br /&gt; setUpOrientationListener : function() {&lt;br /&gt;  // add listener to window if it's orientation-capable&lt;br /&gt;  if( window.orientation !== undefined )&lt;br /&gt;  {&lt;br /&gt;   var self = this; // handles scope&lt;br /&gt;   window.onorientationchange = function (event)&lt;br /&gt;   {&lt;br /&gt;    if ( Math.abs( window.orientation ) % 180 == 90 )&lt;br /&gt;    {&lt;br /&gt;     self.orientation = self.LANDSCAPE;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;     self.orientation = self.PORTRAIT;&lt;br /&gt;    }&lt;br /&gt;    // send out custom event&lt;br /&gt;    var containerNode = $$('body');&lt;br /&gt;    containerNode[0].fire("app:orientationchange", { orientation: self.orientation });&lt;br /&gt;   }&lt;br /&gt;   // make sure local flag is set right away&lt;br /&gt;   window.onorientationchange(null);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;// example code for listening to custom event that fires on orientation change&lt;br /&gt;document.observe("app:orientationchange", function(event) {&lt;br /&gt; console.log( "Tag " + event.target.tagName + " with id of " + event.target.id + " says the orientation is now " + event.memo.orientation + ".");&lt;br /&gt;});&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;// class initialization&lt;br /&gt;var app_state = new AppState(),&lt;br /&gt;*/&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5687261998410304273?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5687261998410304273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/07/javascript-ipad-orientation-class-with.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5687261998410304273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5687261998410304273'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/07/javascript-ipad-orientation-class-with.html' title='Javascript: iPad orientation class with Prototype.js'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-3065385363859647109</id><published>2010-05-27T17:19:00.006-06:00</published><updated>2010-09-14T17:29:04.430-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UISegmentedControl'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: UISegmentedControl with custom colors</title><content type='html'>[&lt;b&gt;UPDATE&lt;/b&gt;]: We had an app approved with this code. Keep in mind that Apple has very inconsistent policies regarding app approval, but it's looking good for now.&lt;br /&gt;&lt;br /&gt;Tasked with building a UISegmentedControl with different colors for selected/unselected buttons, I created a subclass that accomplishes this by digging through the subviews of the segmented control. I can't verify that this will get approved by the mysterious app store process, nor can I say it will function properly if you're using all of the built-in functions of UISegmentedControl (adding/removing segments dynamically will break this code). But for a simple case, it's working well for my purposes. Here we go:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CustomSegmentedControl.h&lt;/b&gt; :&lt;br /&gt;&lt;pre&gt;#import &lt;Foundation/Foundation.h&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@interface CustomSegmentedControl : UISegmentedControl {&lt;br /&gt; &lt;br /&gt; UIColor *offColor;&lt;br /&gt; UIColor *onColor;&lt;br /&gt; &lt;br /&gt; BOOL hasSetSelectedIndexOnce;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;-(id)initWithItems:(NSArray *)items offColor:(UIColor*)offcolor onColor:(UIColor*)oncolor;&lt;br /&gt;-(void)setInitialMode;&lt;br /&gt;-(void)setToggleHiliteColors;&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;CustomSegmentedControl.m&lt;/b&gt; :&lt;br /&gt;&lt;pre&gt;#import "CustomSegmentedControl.h"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@implementation CustomSegmentedControl&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-(id)initWithItems:(NSArray *)items offColor:(UIColor*)offcolor onColor:(UIColor*)oncolor {&lt;br /&gt; if (self = [super initWithItems:items]) {&lt;br /&gt;        // Initialization code&lt;br /&gt;  offColor = [offcolor retain];&lt;br /&gt;  onColor = [oncolor retain];&lt;br /&gt;  hasSetSelectedIndexOnce = NO;&lt;br /&gt;  [self setInitialMode];&lt;br /&gt;  [self setSelectedSegmentIndex:0];  // default to first button, or the coloring gets all whacked out :(&lt;br /&gt;    }&lt;br /&gt;    return self;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;-(void)setInitialMode&lt;br /&gt;{&lt;br /&gt; // set essential properties&lt;br /&gt; [self setBackgroundColor:[UIColor clearColor]];&lt;br /&gt; [self setSegmentedControlStyle:UISegmentedControlStyleBar];&lt;br /&gt; &lt;br /&gt; // loop through children and set initial tint&lt;br /&gt; for( int i = 0; i &lt; [self.subviews count]; i++ )&lt;br /&gt; {&lt;br /&gt;  [[self.subviews objectAtIndex:i] setTintColor:nil];&lt;br /&gt;  [[self.subviews objectAtIndex:i] setTintColor:offColor];&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; // listen for updates&lt;br /&gt; [self addTarget:self action:@selector(setToggleHiliteColors) forControlEvents:UIControlEventValueChanged];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;-(void)setToggleHiliteColors&lt;br /&gt;{&lt;br /&gt; // get current toggle nav index&lt;br /&gt; int index = self.selectedSegmentIndex;&lt;br /&gt; int numSegments = [self.subviews count];&lt;br /&gt; &lt;br /&gt; for( int i = 0; i &lt; numSegments; i++ )&lt;br /&gt; {&lt;br /&gt;  // reset color&lt;br /&gt;  [[self.subviews objectAtIndex:i] setTintColor:nil];&lt;br /&gt;  [[self.subviews objectAtIndex:i] setTintColor:offColor];&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if( hasSetSelectedIndexOnce )&lt;br /&gt; {&lt;br /&gt;  // this is super weird - the subviews array is backwards... so deal with it like that&lt;br /&gt;  [[self.subviews objectAtIndex: numSegments - 1 - index] setTintColor:onColor];&lt;br /&gt; }&lt;br /&gt; else&lt;br /&gt; {&lt;br /&gt;  // ...but the very first time, they're the expected order :-/&lt;br /&gt;  [[self.subviews objectAtIndex: index] setTintColor:onColor];&lt;br /&gt;  hasSetSelectedIndexOnce = YES;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@end &lt;br /&gt;&lt;/pre&gt;&lt;b&gt;And to initialize&lt;/b&gt; :&lt;pre&gt;NSArray *toggleItems = [[NSArray alloc] initWithObjects:@"One",@"Two",@"Three",nil];&lt;br /&gt;CustomSegmentedControl *toggleNav = [[CustomSegmentedControl alloc] initWithItems:toggleItems offColor:[UIColor blackColor] onColor:[UIColor redColor] ];&lt;br /&gt;[toggleNav addTarget:self action:@selector(handleToggleNav:) forControlEvents:UIControlEventValueChanged];&lt;br /&gt;[toggleNav setFrame:CGRectMake(52, 8, 211, 25)]; &lt;br /&gt;[self.view addSubview:toggleNav];&lt;br /&gt;[toggleNav release];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Otherwise, follow the documentation for a UISegmentedControl, and enjoy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-3065385363859647109?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/3065385363859647109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/05/iphone-uisegmentedcontrol-custom-colors.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3065385363859647109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/3065385363859647109'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/05/iphone-uisegmentedcontrol-custom-colors.html' title='iPhone: UISegmentedControl with custom colors'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6643167767028013813</id><published>2010-05-27T16:41:00.000-06:00</published><updated>2010-05-27T16:41:50.541-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='UITextField'/><category scheme='http://www.blogger.com/atom/ns#' term='textfield'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Bug in UITextField component - setTextColor not working</title><content type='html'>I'm working on a form for an iPhone app that does real-time form validation to let the user know if they're trying to create an account with a username that already exists. To let the user know that a username is already taken, I set the UITextField textColor property to red:&lt;br /&gt;&lt;pre&gt;#define kColorRedError [UIColor colorWithRed:1 green:0 blue:0 alpha:1.0]&lt;br /&gt;//... UITextField *username = [[UITextField alloc] initWithFrame:CGRectMake(12, 14, 296, 30)];&lt;br /&gt;[username setTextColor:kColorRedError];&lt;/pre&gt;This wouldn't update until I typed another letter into the UITextField, so quite often it would display an error when it shouldn't, and vice versa. I tried using setNeedsDisplay and some other bits of code to try to force a display update after setting the text color. Nothing worked, until I tried this:&lt;br /&gt;&lt;pre&gt;[password setTextColor:kColorRedError];&lt;br /&gt;username.text = username.text;&lt;/pre&gt;...Quite absurd, but forces a redraw on the component. Gotta love those Apple components ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6643167767028013813?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6643167767028013813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/05/iphone-bug-in-uitextfield-component.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6643167767028013813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6643167767028013813'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/05/iphone-bug-in-uitextfield-component.html' title='iPhone: Bug in UITextField component - setTextColor not working'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-8169553092063456408</id><published>2010-04-21T18:59:00.001-06:00</published><updated>2010-04-21T19:00:59.229-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uibutton'/><category scheme='http://www.blogger.com/atom/ns#' term='uiview'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='block'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Subviews in UIButtons block the touch, unless...</title><content type='html'>If you add a UIView or other UIView subclass to a UIButton, the UIView object will block touches/clicks on the UIButton. There's a simple fix to ensure that subviews in your UIButton don't interfere. In the following case, I have a subclass of UIView that loads an image from the web (WebImage), that's created inside a subclass of UIButton:&lt;br /&gt;&lt;pre&gt;WebImage *thumb = [[WebImage alloc] initWithFrame:CGRectMake(1, 1, 94, 94) andImageUrl:@"http://mysite.com/thumbnail.png"];&lt;br /&gt;[self addSubview:thumb];&lt;br /&gt;&lt;b&gt;thumb.userInteractionEnabled = NO;&lt;br /&gt;thumb.exclusiveTouch = NO;&lt;/b&gt;&lt;br /&gt;[thumb release]; &lt;br /&gt;&lt;/pre&gt;All you need to do is set &lt;b&gt;userInteractionEnabled&lt;/b&gt; and &lt;b&gt;exclusiveTouch&lt;/b&gt; to NO or FALSE, and the subview will no longer block your button.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-8169553092063456408?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/8169553092063456408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/04/iphone-subviews-in-uibuttons-block.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8169553092063456408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8169553092063456408'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/04/iphone-subviews-in-uibuttons-block.html' title='iPhone: Subviews in UIButtons block the touch, unless...'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-8112464834208156265</id><published>2010-04-19T16:25:00.000-06:00</published><updated>2010-04-19T16:25:39.152-06:00</updated><title type='text'>iPhone: You can't have a UIView subclass named "WebView"</title><content type='html'>Good lord, this wasted half a day. I was creating a UIView subclass to hold a UIWebView, and named it "WebView". Not too abstract, right? I kept getting the following cryptic error: &lt;br /&gt;&lt;pre&gt;*** -[WebView _isAncestorOfFirstResponder]: unrecognized selector sent to instance 0x463a7b0&lt;br /&gt;*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[WebView _isAncestorOfFirstResponder]: unrecognized selector sent to instance 0x463a7b0'&lt;br /&gt;&lt;/pre&gt;I renamed my class "WebViewView" and no more errors. Thanks for the shitty error messages Apple!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-8112464834208156265?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/8112464834208156265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/04/iphone-you-cant-have-uiview-subclass.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8112464834208156265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/8112464834208156265'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/04/iphone-you-cant-have-uiview-subclass.html' title='iPhone: You can&apos;t have a UIView subclass named &quot;WebView&quot;'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-4026722608508866792</id><published>2010-04-14T19:24:00.000-06:00</published><updated>2010-04-14T19:24:08.873-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='itouch'/><category scheme='http://www.blogger.com/atom/ns#' term='idevice'/><category scheme='http://www.blogger.com/atom/ns#' term='detection'/><category scheme='http://www.blogger.com/atom/ns#' term='phone call'/><category scheme='http://www.blogger.com/atom/ns#' term='ipod'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='ipad'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone/iTouch/iPad: Check for the ability to make a phone call</title><content type='html'>I came across a situation where I wanted to lay out different buttons in case the iDevice (iPod Touch or iPad) can run my app, but can't make a phone call. The iPhone will display a "Call Store" button, but other devices won't. For a simple check, look at the following code, which checks for the device name, and looks for "iPhone" at the beginning of the string. It's a very simple implementation, but I didn't need further detection functionality for this project.&lt;br /&gt;&lt;pre&gt;// check iDevice model for calling capability and initially assume it's an iPhone&lt;br /&gt;NSString *model= [[UIDevice currentDevice] model];&lt;br /&gt;BOOL canMakeCalls = YES;&lt;br /&gt;//model = @"iTouch"; // manual test for non-iPhones in simulator&lt;br /&gt;if ( ![model hasPrefix:@"iPhone"] ) canMakeCalls = NO;&lt;br /&gt;[model release];&lt;br /&gt;&lt;/pre&gt;Then you can conditionally display or disable UI elements depending on whether it's for the iPhone only. This can obviously be customized further and more robustly, but for something quick and easy, I hope you find it useful. Check out &lt;a href="http://iphonedevelopment.blogspot.com/2009/05/device-detection.html" target="_blank"&gt;this blog&lt;/a&gt; for a much more detailed detection class.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-4026722608508866792?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/4026722608508866792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/04/iphoneitouchipad-check-for-ability-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4026722608508866792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4026722608508866792'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/04/iphoneitouchipad-check-for-ability-to.html' title='iPhone/iTouch/iPad: Check for the ability to make a phone call'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6348124717975898042</id><published>2010-03-19T00:09:00.001-06:00</published><updated>2010-04-14T19:02:08.935-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='masking'/><category scheme='http://www.blogger.com/atom/ns#' term='problems'/><category scheme='http://www.blogger.com/atom/ns#' term='flash player 10'/><category scheme='http://www.blogger.com/atom/ns#' term='fp10'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>Actionscript 3: Masking in Native 3D Issue in FP10</title><content type='html'>Today I tried to mask a Sprite that was in a container that had native 3d rotation applied - i.e. a parent Sprite had some rotationX and rotationY. The masking wasn't working, but it turns out that it was only not working because another Sprite within the same parent container had a 3D "z" value set. In order to get the masking to behave properly, I had to nest the Sprite and its mask in another Sprite, so that no sibling clips had z-positioning within the same immediate parent clip. Hopefully this little note saves someone the time it took for me to realize what the issue was.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6348124717975898042?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6348124717975898042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/03/actionscript-3-masking-in-native-3d.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6348124717975898042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6348124717975898042'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/03/actionscript-3-masking-in-native-3d.html' title='Actionscript 3: Masking in Native 3D Issue in FP10'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-715381125910377688</id><published>2010-03-12T08:53:00.002-07:00</published><updated>2010-05-27T12:11:42.301-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Get the class name of an object</title><content type='html'>Sometimes you want to know what type of object something is, when pulling it out of an array. In Obj-c there's a simple way to do that:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;NSLog(@"object type = %@", [[myObject class] className]);&lt;/pre&gt;or&lt;br /&gt;&lt;pre&gt;NSLog(@"object type = %@", [[myObject class] description]);&lt;/pre&gt;or!&lt;br /&gt;&lt;pre&gt;if( [[myArray objectAtIndex:i] isKindOfClass:NSClassFromString(@"MyCustomClass")] ) { NSLog(@"it's a MyCustomClass"); }&lt;/pre&gt;&lt;br /&gt;Easy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-715381125910377688?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/715381125910377688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2010/03/iphone-get-class-name-of-object.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/715381125910377688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/715381125910377688'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2010/03/iphone-get-class-name-of-object.html' title='iPhone: Get the class name of an object'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5354524271543906262</id><published>2009-09-02T13:45:00.000-06:00</published><updated>2009-09-02T13:46:23.829-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='papervision'/><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='papervision3d'/><category scheme='http://www.blogger.com/atom/ns#' term='hyperlink'/><category scheme='http://www.blogger.com/atom/ns#' term='textfield'/><category scheme='http://www.blogger.com/atom/ns#' term='link'/><category scheme='http://www.blogger.com/atom/ns#' term='click'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Papervision3d: html links in a TextField</title><content type='html'>Papervision is fun, and the most commonly used 3D library in Flash. The developers have done an amazing job taking care of so many issues that arise when rendering multiple interactive objects to one BitmapData object. For example, if you create a 2D Sprite, put a button inside it somewhere, and then use that Sprite as a MovieMaterial texture for a 3D object, the MouseEvent listeners are automatically handled, and your buttons in the texture work as expected, which is awesome. One major issue along these lines is that if you have an html-enabled TextField with active hyperlinks, this button functionality does not get forwarded through the Papervision core. I saw some code that &lt;a href="http://www.brunoimbrizi.com/" target="_blank"&gt;another developer&lt;/a&gt; had posted on a forum, and I rewrote it to work nicely with multiple links. The idea is that you can find the character positions of a hyperlink's text in the TextField, and draw buttons as Sprites in the 2D texture, on top of the TextField, so that your hyperlinks will have an active hit state and work inside a 3D object. I also included a dispose function to clean up, and have rollover listeners to enable the hand cursor in the PV3D viewport, which happens in a different class. This all could've been done a little cleaner with multiple classes and more regular expressions, but I wanted to keep it really simple and easy to implement and garbage collect. Here's the code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected var _htmlButtons:Array;&lt;br /&gt;protected var _htmlButtonLinks:Array;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Create hit areas for html links - since they aren't handled automatically by PV&lt;br /&gt; */  &lt;br /&gt;protected function activateHrefs( textField:TextField ):void&lt;br /&gt;{&lt;br /&gt; var htmlTxtStr:String = textField.htmlText;&lt;br /&gt; var plainTxtStr:String = textField.text;&lt;br /&gt; var linkOpens:Array = getIndexesOfArray( htmlTxtStr, "&amp;lt;a " );&lt;br /&gt; var linkCloses:Array = getIndexesOfArray( htmlTxtStr, "&amp;lt;/a&amp;gt;" );&lt;br /&gt; &lt;br /&gt; _htmlButtons = new Array();&lt;br /&gt; _htmlButtonLinks = new Array();&lt;br /&gt; &lt;br /&gt; // helps step through and not repeat duplicate links&lt;br /&gt; var lastPlanTextIndex:int = 0;&lt;br /&gt; &lt;br /&gt; // loop through links found&lt;br /&gt; for( var i:int = 0; i &lt; linkOpens.length; i++ )&lt;br /&gt; {&lt;br /&gt;  // create button&lt;br /&gt;  var button:Sprite = new Sprite();&lt;br /&gt;  button.x = textField.x;&lt;br /&gt;  button.y = textField.y;&lt;br /&gt;  this.addChild( button );&lt;br /&gt;  &lt;br /&gt;  // get text position in html text&lt;br /&gt;  var firstCharIndex:int = linkOpens[i];&lt;br /&gt;  var linkLength:int = linkCloses[i] - linkOpens[i] + 4;&lt;br /&gt;  &lt;br /&gt;  // pull out string inside open and close tags&lt;br /&gt;  var linkString:String = htmlTxtStr.substr( firstCharIndex, linkLength );&lt;br /&gt;  &lt;br /&gt;  // get href from &amp;lt;a&amp;gt; tag&lt;br /&gt;  var hrefPattern:RegExp = /href=['"]\S+['"]/i;&lt;br /&gt;  var hrefs:Array = linkString.match( hrefPattern );&lt;br /&gt;  var href:String = ( hrefs ) ? hrefs[0].substring(6, hrefs[0].length - 1) : "";&lt;br /&gt;  &lt;br /&gt;  // strip tags&lt;br /&gt;  linkString = linkString.substr( linkString.indexOf( "&amp;gt;" ) + 1 ); // chop open tag&lt;br /&gt;  linkString = linkString.substr( 0, linkString.length - 4 ); // chop end tag&lt;br /&gt;  &lt;br /&gt;  // find link text in non-html text&lt;br /&gt;  var linkStringPlainTextIndex:int = plainTxtStr.indexOf( linkString, lastPlanTextIndex );&lt;br /&gt;  lastPlanTextIndex = linkStringPlainTextIndex;&lt;br /&gt;  &lt;br /&gt;  // draw rects for letters&lt;br /&gt;  button.graphics.beginFill(0xFF0000, 0);&lt;br /&gt;  for( var j:int = linkStringPlainTextIndex; j &lt; linkStringPlainTextIndex + linkString.length; j++ )&lt;br /&gt;  {&lt;br /&gt;   var charRect:Rectangle = textField.getCharBoundaries(j);&lt;br /&gt;   if( charRect ) button.graphics.drawRect(charRect.x, charRect.y, charRect.width, charRect.height);&lt;br /&gt;  }&lt;br /&gt;  button.graphics.endFill();&lt;br /&gt;  &lt;br /&gt;  // add listeners&lt;br /&gt;  button.addEventListener( MouseEvent.CLICK, onHyperlinkClick );&lt;br /&gt;  button.addEventListener( MouseEvent.MOUSE_OVER, onHtmlLinkOver );&lt;br /&gt;  button.addEventListener( MouseEvent.MOUSE_OUT, onHtmlLinkOut );&lt;br /&gt;     &lt;br /&gt;  // store button and link so we can launch on click&lt;br /&gt;  _htmlButtons.push( button );&lt;br /&gt;  _htmlButtonLinks.push( href );&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Returns an array of all the indexes of needle in haystack&lt;br /&gt; */&lt;br /&gt;protected function getIndexesOfArray( haystack:String, needle:String ) : Array&lt;br /&gt;{&lt;br /&gt; var indexs:Array = new Array();&lt;br /&gt; var startIndex:int = 0;&lt;br /&gt; while( startIndex != -1 )&lt;br /&gt; {&lt;br /&gt;  startIndex = haystack.indexOf( needle, startIndex );&lt;br /&gt;  if( startIndex != -1 )&lt;br /&gt;  {&lt;br /&gt;   indexs.push( startIndex );&lt;br /&gt;   startIndex += 1;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; return indexs;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * simply opens the link&lt;br /&gt; */&lt;br /&gt;protected function onHyperlinkClick( e:MouseEvent ) : void&lt;br /&gt;{&lt;br /&gt; // find button and launch corresponding link&lt;br /&gt; for( var i:int = 0; i &lt; _htmlButtons.length; i++ )&lt;br /&gt; {&lt;br /&gt;  if( e.target == _htmlButtons[i] )&lt;br /&gt;  {&lt;br /&gt;   navigateToURL( new URLRequest( _htmlButtonLinks[i] ), '_blank' );&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected function onHtmlLinkOver( e:MouseEvent ):void&lt;br /&gt;{&lt;br /&gt; // dispatch an Event to tell the PV3D viewport to enable the hand cursor:&lt;br /&gt; // ( _pvView as BasicView).viewport.buttonMode = true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected function onHtmlLinkOut( e:MouseEvent ):void&lt;br /&gt;{&lt;br /&gt;// dispatch an Event to tell the PV3D viewport to disable the hand cursor:&lt;br /&gt;// ( _pvView as BasicView).viewport.buttonMode = false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * clean up when if leave the papervision section&lt;br /&gt; */&lt;br /&gt;public function dispose():void&lt;br /&gt;{&lt;br /&gt; // kill html hyperlink buttons&lt;br /&gt; if(_htmlButtons != null) {&lt;br /&gt;  for( var i:int = 0; i &lt; _htmlButtons.length; i++ )&lt;br /&gt;  {&lt;br /&gt;   _htmlButtons[i].removeEventListener( MouseEvent.CLICK, onHyperlinkClick );&lt;br /&gt;   _htmlButtons[i].removeEventListener( MouseEvent.MOUSE_OVER, onHtmlLinkOver );&lt;br /&gt;   _htmlButtons[i].removeEventListener( MouseEvent.MOUSE_OUT, onHtmlLinkOut );&lt;br /&gt;  }&lt;br /&gt;  _htmlButtons.splice( 0 );&lt;br /&gt;  _htmlButtonLinks.splice(0);&lt;br /&gt;  _htmlButtons = null;&lt;br /&gt;  _htmlButtonLinks = null;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5354524271543906262?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5354524271543906262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-papervision3d-html-links.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5354524271543906262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5354524271543906262'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-papervision3d-html-links.html' title='ActionScript 3: Papervision3d: html links in a TextField'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1399966422053641648</id><published>2009-09-01T14:38:00.003-06:00</published><updated>2009-09-01T15:14:10.495-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='array'/><category scheme='http://www.blogger.com/atom/ns#' term='random number'/><category scheme='http://www.blogger.com/atom/ns#' term='weighted'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Choose a random item from an Array, with weighting</title><content type='html'>It's very common to simply choose a random item from an Array, using a random number. But what if we want change the probabilities that certain items will be chosen? I've written a little function that takes an Array of weights (Numbers), which correspond to the Array of items you'd like to choose from, and returns an index to pull a random, weighted item from the source Array. Check out the example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// our array of items&lt;br /&gt;var fruits:Array = ['apple','orange','banana','mango'];&lt;br /&gt;// our array of weights&lt;br /&gt;var weights:Array = [20,10,40,30];&lt;br /&gt;// pick a random fruit, based on weights, with bananas most likely to get picked&lt;br /&gt;var myFruit:String = fruits[ randomIndexByWeights( weights ) ];&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Takes an array of weights, and returns a random index based on the weights&lt;br /&gt; */&lt;br /&gt;private function randomIndexByWeights( weights:Array ) : int&lt;br /&gt;{&lt;br /&gt; // add weights&lt;br /&gt; var weightsTotal:Number = 0;&lt;br /&gt; for( var i:int = 0; i &lt; weights.length; i++ ) weightsTotal += weights[i];&lt;br /&gt; // pick a random number in the total range&lt;br /&gt; var rand:Number = Math.random() * weightsTotal;&lt;br /&gt; // step through array to find where that would be &lt;br /&gt; weightsTotal = 0;&lt;br /&gt; for( i = 0; i &lt; weights.length; i++ )&lt;br /&gt; {&lt;br /&gt;  weightsTotal += weights[i];&lt;br /&gt;  if( rand &lt; weightsTotal ) return i;&lt;br /&gt; }&lt;br /&gt; // if random num is exactly = weightsTotal&lt;br /&gt; return weights.length - 1;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can see that the weights array must be the same length as the data array that you're choosing from. Note that in the example, my weights add up to 100, but you can use any scale that you'd like, as the weights are added up, and a random number is chosen in that scale.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1399966422053641648?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1399966422053641648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-choose-random-item-from.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1399966422053641648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1399966422053641648'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-choose-random-item-from.html' title='ActionScript 3: Choose a random item from an Array, with weighting'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1347660311390790129</id><published>2009-09-01T14:32:00.003-06:00</published><updated>2009-09-01T14:38:15.381-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='array'/><category scheme='http://www.blogger.com/atom/ns#' term='shuffle'/><category scheme='http://www.blogger.com/atom/ns#' term='randomize'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Shuffle/randomize any Array</title><content type='html'>A quick little function for randomizing/shuffling an Array that contains objects or primitive of any data type:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public static function randomizeArray( arr:Array ):void&lt;br /&gt;{&lt;br /&gt; for( var i:int = 0; i &lt; arr.length; i++ )&lt;br /&gt; {&lt;br /&gt;  var tmp:* = arr[i];&lt;br /&gt;  var randomIndex:int = Math.round( Math.random() * ( arr.length - 1 ) );&lt;br /&gt;  arr[i] = arr[randomIndex];&lt;br /&gt;  arr[randomIndex] = tmp;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can see that it crawls through an Array, swapping each position with another, random position in the Array.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1347660311390790129?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1347660311390790129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-shufflerandomize-any.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1347660311390790129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1347660311390790129'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-shufflerandomize-any.html' title='ActionScript 3: Shuffle/randomize any Array'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2888423098128103005</id><published>2009-09-01T09:35:00.005-06:00</published><updated>2009-09-01T21:07:04.581-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='suffix'/><category scheme='http://www.blogger.com/atom/ns#' term='random number'/><category scheme='http://www.blogger.com/atom/ns#' term='textual'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><title type='text'>ActionScript 3: Adding a textual suffix to numbers</title><content type='html'>If you need to write out a number with a textual suffix, like "25th" or "173rd", there's a little logic that will make this really easy. Check it out:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// suffixes corresponding to the last digit of a number: 0-9&lt;br /&gt;private static const NUMBER_SUFFIXES:Array = [ 'th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th' ];&lt;br /&gt;&lt;br /&gt;private function getNumberSuffix( value : int ) : String&lt;br /&gt;{&lt;br /&gt; // handle most cases by modding by ten&lt;br /&gt; var suffix:String = NUMBER_SUFFIXES[ value % 10 ];&lt;br /&gt; if( value % 100 &gt;= 11 &amp;&amp; value % 100 &lt;= 13 ) suffix = 'th';  // handle 11-13&lt;br /&gt; if( value == 0 ) suffix = '';         // handle zero&lt;br /&gt; return suffix;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2888423098128103005?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2888423098128103005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-adding-textual-suffix-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2888423098128103005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2888423098128103005'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/09/actionscript-3-adding-textual-suffix-to.html' title='ActionScript 3: Adding a textual suffix to numbers'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5952160034396643111</id><published>2009-08-31T16:15:00.004-06:00</published><updated>2009-09-01T09:07:25.102-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='value'/><category scheme='http://www.blogger.com/atom/ns#' term='random number'/><category scheme='http://www.blogger.com/atom/ns#' term='percentage'/><title type='text'>ActionScript 3: Get the percentage of a value within a number range</title><content type='html'>Sometimes, when creating UI elements or performing geometric calculations based on the sizes or positions of objects (or lots of other tasks), it's useful to find the percentage of a number within a range of 2 other numbers. Use this function to easily relate these values:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;/**&lt;br /&gt; * Returns a percentage of a value in between 2 other numbers.&lt;br /&gt; * @param bottomRange  low end of the range.&lt;br /&gt; * @param  topRange  top end of the range.&lt;br /&gt; * @param  valueInRange value to find a range percentage of.&lt;br /&gt; * @return The percentage of valueInRange in the range.&lt;br /&gt; *  @use getPercentWithinRange( 50, 150, 100 );  // displays 50&lt;br /&gt; */&lt;br /&gt;public static function getPercentWithinRange( bottomRange:Number, topRange:Number, valueInRange:Number ):Number&lt;br /&gt;{&lt;br /&gt; // normalize values to work off zero&lt;br /&gt; if( bottomRange &lt; 0 )&lt;br /&gt; {&lt;br /&gt;  var addToAll:Number = Math.abs( bottomRange );&lt;br /&gt;  bottomRange += addToAll;&lt;br /&gt;  topRange += addToAll;&lt;br /&gt;  valueInRange += addToAll;&lt;br /&gt; }&lt;br /&gt; else if( bottomRange &gt; 0 )&lt;br /&gt; {&lt;br /&gt;  var subFromAll:Number = Math.abs( bottomRange );&lt;br /&gt;  bottomRange -= subFromAll;&lt;br /&gt;  topRange -= subFromAll;&lt;br /&gt;  valueInRange -= subFromAll;&lt;br /&gt; }&lt;br /&gt; // simple calc to get percentage &lt;br /&gt; return 100 * ( valueInRange / ( topRange - bottomRange ) );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5952160034396643111?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5952160034396643111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/08/actionscript-3-get-percentage-of-value.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5952160034396643111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5952160034396643111'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/08/actionscript-3-get-percentage-of-value.html' title='ActionScript 3: Get the percentage of a value within a number range'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6333426270114507287</id><published>2009-08-31T09:12:00.004-06:00</published><updated>2009-08-31T11:41:25.568-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='ease'/><category scheme='http://www.blogger.com/atom/ns#' term='tween'/><category scheme='http://www.blogger.com/atom/ns#' term='float'/><category scheme='http://www.blogger.com/atom/ns#' term='easing'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Constant easing function</title><content type='html'>Sometimes you want to ease a numeric variable or object property to a new value. Typically, you would do this with a tween, via the built-in Tween object, or a 3rd party tween library like Tweener or TweenLite/TweenMax. Sometimes, for a fluid interface, you might want different properties constantly easing (floating) towards their current target destination. In this situation, you would want to interpolate the values incrementally towards the target using the Event.ENTER_FRAME listener. I wrote a nice little function that will take the current value, the target value, and an optional easing value (where higher numbers increase the time to reach the target value), and ease the property towards the target. Check it out:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private function easeTo( current:Number, target:Number, easeFactor:Number = 10 ):Number&lt;br /&gt;{  &lt;br /&gt; return current -= ( ( current - target ) / easeFactor );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// usage:&lt;br /&gt;this.addEventListener( Event.ENTER_FRAME, onEnterFrameLoop );&lt;br /&gt;&lt;br /&gt;private function onEnterFrameLoop( e:Event ):void {&lt;br /&gt; mySprite.x = easeTo( mySprite.x, 200, 5 );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, wherever mySprite is, it will smoothly tween towards the x destination of 200. This can be applied to any numeric property.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6333426270114507287?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6333426270114507287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/08/actionscript-3-constant-easing-function.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6333426270114507287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6333426270114507287'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/08/actionscript-3-constant-easing-function.html' title='ActionScript 3: Constant easing function'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5177848155807399370</id><published>2009-06-18T14:49:00.003-06:00</published><updated>2009-06-18T15:00:43.682-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='amazonaws'/><category scheme='http://www.blogger.com/atom/ns#' term='crossdomain.xml'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Actionscript: Crossdomain issue when loading Twitter user icons</title><content type='html'>When building a new Flash piece, I ran into a crossdomain issue when trying to load the user icon images that come back from the Twitter API. After some searching, I found that by replacing the root of the url, the crossdomain issues are easily solved. Check it out:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var thumbnail:String = "http://s3.amazonaws.com/twitter_production/profile_images/252274568/profile_image_normal.jpg";&lt;br /&gt;thumbnail = thumbnail.replace(/http:\/\/s3.amazonaws.com\/twitter_production\//g, 'http://twitter_production.s3.amazonaws.com/');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I was surprised it was this easy, but by moving the "twitter_production" portion of the path to the front of the subdomain, you now get a good crossdomain.xml here: http://twitter_production.s3.amazonaws.com/crossdomain.xml&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5177848155807399370?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5177848155807399370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/06/actionscript-crossdomain-issue-when.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5177848155807399370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5177848155807399370'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/06/actionscript-crossdomain-issue-when.html' title='Actionscript: Crossdomain issue when loading Twitter user icons'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-7471618295068361508</id><published>2009-05-13T15:50:00.003-06:00</published><updated>2009-05-13T16:05:44.132-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='processing.org'/><category scheme='http://www.blogger.com/atom/ns#' term='generative art'/><category scheme='http://www.blogger.com/atom/ns#' term='processing'/><title type='text'>Processing: Spiral growth generative art</title><content type='html'>A coworker got me excited to play around with &lt;a href="http://www.processing.org/"&gt;Processing&lt;/a&gt; again, and I wrote a couple new generative art scripts. Here's a fun one:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;float x;&lt;br /&gt;float y;&lt;br /&gt;float curRotation;&lt;br /&gt;float rotationVelocity;&lt;br /&gt;float curRadius;&lt;br /&gt;float radiusVelocity;&lt;br /&gt;float radiusThreshold;&lt;br /&gt;float curSize;&lt;br /&gt;float sizeVelocity;&lt;br /&gt;float curRed;&lt;br /&gt;float redVelocity;&lt;br /&gt;float curGreen;&lt;br /&gt;float greenVelocity;&lt;br /&gt;float curBlue;&lt;br /&gt;float blueVelocity;&lt;br /&gt;&lt;br /&gt;void setup(){&lt;br /&gt;size(1000,1000);&lt;br /&gt;smooth();&lt;br /&gt;background(45,0,0);&lt;br /&gt;frameRate(100);&lt;br /&gt;reset();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void draw(){&lt;br /&gt;&lt;br /&gt;x = (width / 2) + sin(curRotation) * curRadius;&lt;br /&gt;y = (height / 2) + cos(curRotation) * curRadius;&lt;br /&gt;&lt;br /&gt;noStroke();&lt;br /&gt;//stroke(100,100,100,150);&lt;br /&gt;fill(curRed,curGreen,curBlue);&lt;br /&gt;ellipse(x,y,curSize,curSize);&lt;br /&gt;&lt;br /&gt;curRadius += radiusVelocity;&lt;br /&gt;curRotation += rotationVelocity;&lt;br /&gt;curSize -= sizeVelocity;&lt;br /&gt;if( curRed &gt; 45 ) curRed -= redVelocity;&lt;br /&gt;curGreen -= greenVelocity;&lt;br /&gt;curBlue -= blueVelocity;&lt;br /&gt;&lt;br /&gt;if( curSize &lt;= 0 ) //curRadius &gt; radiusThreshold ||&lt;br /&gt;{&lt;br /&gt; reset();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void reset(){&lt;br /&gt; curRadius = 0;&lt;br /&gt; curRotation = random(0,3.14*2);&lt;br /&gt; curSize = 20;&lt;br /&gt; sizeVelocity = random(.05, .2);&lt;br /&gt; rotationVelocity = random(.001, .009);&lt;br /&gt; radiusVelocity = random( .1, 2 );&lt;br /&gt; radiusThreshold = random( width / 3, width / 4 );&lt;br /&gt; // make a shade of red&lt;br /&gt; curRed = random(100, 255);&lt;br /&gt; redVelocity = random( .1, 1 );&lt;br /&gt; curGreen = random(0, 50);&lt;br /&gt; greenVelocity = .5 * redVelocity;&lt;br /&gt; curBlue = curGreen;&lt;br /&gt; blueVelocity = greenVelocity;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It ends up looking something like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_EjN6eQMIZW4/SgtD6L1vNiI/AAAAAAAAAAM/jJHZkLQ0SMU/s1600-h/spiralgrowth-01.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 320px;" src="http://1.bp.blogspot.com/_EjN6eQMIZW4/SgtD6L1vNiI/AAAAAAAAAAM/jJHZkLQ0SMU/s320/spiralgrowth-01.jpg" alt="" id="BLOGGER_PHOTO_ID_5335432850440140322" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-7471618295068361508?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/7471618295068361508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/05/processing-spiral-growth-generative-art.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/7471618295068361508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/7471618295068361508'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/05/processing-spiral-growth-generative-art.html' title='Processing: Spiral growth generative art'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_EjN6eQMIZW4/SgtD6L1vNiI/AAAAAAAAAAM/jJHZkLQ0SMU/s72-c/spiralgrowth-01.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-738909924560681598</id><published>2009-04-22T16:17:00.006-06:00</published><updated>2009-04-22T16:53:19.853-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='502 error'/><category scheme='http://www.blogger.com/atom/ns#' term='crossdomain.xml'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='base'/><title type='text'>ActionScript 3: 502 error on crossdomain.xml request in IE</title><content type='html'>My team and I ran into a very strange security error today while testing our new Flash projects that load assets from external URLs. It only showed up in IE, which was quite mystifying. We had taken care of all of our crossdomain issues by updating our crossdomain.xml files, adding proper security code to all of our media loads as such:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new LoaderContext( true, ApplicationDomain.currentDomain, SecurityDomain.currentDomain );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But something wasn't right. I installed Fiddler, which is a super handy tool for debugging in IE, since FireBug is only available for FireFox. We found that IE was making the request for crossdomain.xml, but the server it was requesting from was the name of the media file, and not the actual server. After a bit of poking around we found that the CMS we were using was automatically formatting the Flash embed code, and was adding this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;#60;param value="" name="base"&amp;#62;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This simple embed param caused the super weird behavior, only in IE. Hopefully this may be helpful to someone who runs into the same issue. Yay IE!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-738909924560681598?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/738909924560681598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/04/actionscript-3-502-error-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/738909924560681598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/738909924560681598'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/04/actionscript-3-502-error-on.html' title='ActionScript 3: 502 error on crossdomain.xml request in IE'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5728987164613572389</id><published>2009-04-21T17:17:00.010-06:00</published><updated>2009-04-22T16:17:06.461-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='animate'/><category scheme='http://www.blogger.com/atom/ns#' term='settimeout'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Javascript: scroll / animate a background image</title><content type='html'>I got the urge to add a little flavor to a repeating background image on one of my personal sites. When you roll over the div with your mouse, the image starts scrolling by incrementing the background-position css. First you need a div with a background-image, a background-position, and an id of "header":&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#header {&lt;br /&gt;background-image:url(../images/site-header-single.gif);&lt;br /&gt;background-position:-73px 0;&lt;br /&gt;background-repeat:repeat-x;&lt;br /&gt;width:752px;&lt;br /&gt;height:242px;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then you need to attach the mouse rollover functionality to the header - I did this dynamically with &lt;a href="http://protoculous.wikeo.be/"&gt;protoculous&lt;/a&gt;, as seen below in the final Event.observe method. The rest is simple: start a timer, grab the background position offset from the css, increment, and apply the reassembled css. Easy:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// setTimeout variable for clearing on rollout&lt;br /&gt;var headerTimeout;&lt;br /&gt;&lt;br /&gt;function addHeaderBehavior() {&lt;br /&gt; Event.observe( $('header'), 'mouseover', startHeaderAnim, false);&lt;br /&gt; Event.observe( $('header'), 'mouseout', stopHeaderAnim, false);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function startHeaderAnim() {&lt;br /&gt; headerTimeout = setTimeout( "incrementHeader()", 50 );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function incrementHeader()&lt;br /&gt;{&lt;br /&gt; // get x variable of background-position&lt;br /&gt; var bgOffsets = $('header').getStyle('background-position').split(' ');&lt;br /&gt; var offsetX = bgOffsets[0];&lt;br /&gt; var offsetY = bgOffsets[1];&lt;br /&gt; // strip px and increment&lt;br /&gt; offsetX = offsetX.replace( /px/, '' );&lt;br /&gt; offsetX = parseInt( offsetX ) + 1;&lt;br /&gt; // update style&lt;br /&gt; $('header').setStyle( { backgroundPosition:offsetX + 'px  ' + offsetY } );&lt;br /&gt; &lt;br /&gt; startHeaderAnim();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function stopHeaderAnim(event) {&lt;br /&gt; clearTimeout( headerTimeout );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Event.observe(window, 'load', addHeaderBehavior, false);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5728987164613572389?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5728987164613572389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/04/javascript-scroll-animate-background.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5728987164613572389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5728987164613572389'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/04/javascript-scroll-animate-background.html' title='Javascript: scroll / animate a background image'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5520985240496281599</id><published>2009-04-02T14:55:00.005-06:00</published><updated>2009-04-02T15:37:41.044-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='generate'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='drawing'/><category scheme='http://www.blogger.com/atom/ns#' term='bitmap'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Easily generate code to draw a complex image</title><content type='html'>In Flash, I always do everything in a programmatic way if possible. This includes drawing shapes with code instead of having library items. This is especially true, now that the preferred method of compiling is using the Flex mxmlc compiler. Sometimes, though, certain things are too much of a pain to draw pixel by pixel. No longer though, as there's a REALLY simple way to generate the code to draw complex shapes for you. &lt;br /&gt;&lt;br /&gt;Step 1: save a .png of the image you want drawn.&lt;br /&gt;Step 2: open Flash, and drop your image into the library, giving it a linkage ID of "MyGraphic".&lt;br /&gt;Step 3: drop the following code into the actions panel and publish.&lt;br /&gt;Step 4: copy the output code and apply it to a BitmapData object in your project.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var mc : MyGraphic = new MyGraphic( null, null ); &lt;br /&gt;for( var i:int = 0; i &lt; mc.width; i ++)&lt;br /&gt;{&lt;br /&gt;    for( var j:int = 0; j &lt; mc.height; j ++)&lt;br /&gt;    {&lt;br /&gt;        if( mc.getPixel32( i, j ) != 0 ) trace( "bmp.setPixel32( "+i+", "+j+", "+mc.getPixel32( i, j )+" );" );&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;the resulting code in my case looked like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public static function drawVideoPlayhead():Bitmap&lt;br /&gt;{&lt;br /&gt; var bitmap:Bitmap = new Bitmap();&lt;br /&gt; var bmp:BitmapData = new BitmapData( 7, 8, true, 0x00000000 );&lt;br /&gt;&lt;br /&gt; // begin generated code&lt;br /&gt; bmp.setPixel32( 0, 3, 4289309097 );&lt;br /&gt; bmp.setPixel32( 0, 4, 4288322202 );&lt;br /&gt; bmp.setPixel32( 0, 5, 4287664272 );&lt;br /&gt; bmp.setPixel32( 0, 6, 4286874756 );&lt;br /&gt; bmp.setPixel32( 1, 2, 4290888129 );&lt;br /&gt; bmp.setPixel32( 1, 3, 4291085508 );&lt;br /&gt; bmp.setPixel32( 1, 4, 4290822336 );&lt;br /&gt; bmp.setPixel32( 1, 5, 4290032820 );&lt;br /&gt; bmp.setPixel32( 1, 6, 4288256409 );&lt;br /&gt; bmp.setPixel32( 1, 7, 4286874756 );&lt;br /&gt; bmp.setPixel32( 2, 1, 4291677645 );&lt;br /&gt; bmp.setPixel32( 2, 2, 4291875024 );&lt;br /&gt; bmp.setPixel32( 2, 3, 4291677645 );&lt;br /&gt; bmp.setPixel32( 2, 4, 4290822336 );&lt;br /&gt; bmp.setPixel32( 2, 5, 4290032820 );&lt;br /&gt; bmp.setPixel32( 2, 6, 4289374890 );&lt;br /&gt; bmp.setPixel32( 2, 7, 4287598479 );&lt;br /&gt; bmp.setPixel32( 3, 0, 4293322470 );&lt;br /&gt; bmp.setPixel32( 3, 1, 4293388263 );&lt;br /&gt; bmp.setPixel32( 3, 2, 4292335575 );&lt;br /&gt; bmp.setPixel32( 3, 3, 4291677645 );&lt;br /&gt; bmp.setPixel32( 3, 4, 4290822336 );&lt;br /&gt; bmp.setPixel32( 3, 5, 4290032820 );&lt;br /&gt; bmp.setPixel32( 3, 6, 4289374890 );&lt;br /&gt; bmp.setPixel32( 3, 7, 4287598479 );&lt;br /&gt; bmp.setPixel32( 4, 1, 4294046193 );&lt;br /&gt; bmp.setPixel32( 4, 2, 4293256677 );&lt;br /&gt; bmp.setPixel32( 4, 3, 4291677645 );&lt;br /&gt; bmp.setPixel32( 4, 4, 4290822336 );&lt;br /&gt; bmp.setPixel32( 4, 5, 4290032820 );&lt;br /&gt; bmp.setPixel32( 4, 6, 4289374890 );&lt;br /&gt; bmp.setPixel32( 4, 7, 4287598479 );&lt;br /&gt; bmp.setPixel32( 5, 2, 4293717228 );&lt;br /&gt; bmp.setPixel32( 5, 3, 4292861919 );&lt;br /&gt; bmp.setPixel32( 5, 4, 4290822336 );&lt;br /&gt; bmp.setPixel32( 5, 5, 4290032820 );&lt;br /&gt; bmp.setPixel32( 5, 6, 4289703855 );&lt;br /&gt; bmp.setPixel32( 5, 7, 4288059030 );&lt;br /&gt; bmp.setPixel32( 6, 3, 4293914607 );&lt;br /&gt; bmp.setPixel32( 6, 4, 4293190884 );&lt;br /&gt; bmp.setPixel32( 6, 5, 4292730333 );&lt;br /&gt; bmp.setPixel32( 6, 6, 4291677645 );&lt;br /&gt; // end generated code&lt;br /&gt; &lt;br /&gt; bitmap.bitmapData = bmp;&lt;br /&gt; return bitmap;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notes: using the setPixel32() function, and defaulting the BitmapData to a background color of 0x00000000 ensures that your Bitmap will have a transparent background. Note that the code here ignores empty pixels for efficiency. Finally, this code could easily be converted to draw into a Shape or Sprite, but for my purposes, bitmaps are usually what I want. Hope you find this useful!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5520985240496281599?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5520985240496281599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/04/actionscript-3-easily-generate-code-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5520985240496281599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5520985240496281599'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/04/actionscript-3-easily-generate-code-to.html' title='ActionScript 3: Easily generate code to draw a complex image'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2941315502294376231</id><published>2009-03-16T18:00:00.004-06:00</published><updated>2009-03-16T18:03:25.280-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='toggle'/><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='boolean'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Toggling a Boolean the easy way</title><content type='html'>This may be common knowledge to some, but I was pretty excited when I realized I didn't need an conditional statement to figure out which direction to toggle a Boolean value. Check it out:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var isTrue:Boolean = true;&lt;br /&gt;isTrue = !isTrue;&lt;br /&gt;trace(isTrue);      // prints "false"&lt;br /&gt;isTrue = !isTrue;&lt;br /&gt;trace(isTrue);      // prints "true"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simplicity is your friend.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2941315502294376231?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2941315502294376231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/03/actionscript-3-toggling-boolean-easy.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2941315502294376231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2941315502294376231'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/03/actionscript-3-toggling-boolean-easy.html' title='ActionScript 3: Toggling a Boolean the easy way'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6557257796984422390</id><published>2009-03-09T13:50:00.002-06:00</published><updated>2009-03-09T14:39:41.299-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xmllist'/><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='node'/><category scheme='http://www.blogger.com/atom/ns#' term='parsing'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript 3: Checking for empty xml nodes</title><content type='html'>When parsing xml in AS3, you grab a leaf node's inner content by using the XML( node ).text() function. You can compare the result with a String, but if you're checking for an empty string, the .text() function doesn't compute, because it returns an XMLList, instead of a String. While a non-empty string comparison works fine between an XMLList and a String, an empty String ( i.e. var mystring:String = ""; ) is not the same as an empty XMLList. To ensure that your comparison works, it's always a good policy to cast your text node to a String. See the example below:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var isEmptyNode:Boolean = false;&lt;br /&gt;if( String( node["myNodeName"].text() ) == "" )&lt;br /&gt;{&lt;br /&gt;    isEmptyNode = true;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6557257796984422390?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6557257796984422390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/03/actionscript-3-checking-for-empty-xml.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6557257796984422390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6557257796984422390'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/03/actionscript-3-checking-for-empty-xml.html' title='ActionScript 3: Checking for empty xml nodes'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-7898984310129519898</id><published>2009-02-04T15:06:00.000-07:00</published><updated>2009-02-04T15:14:47.056-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MPMoviePlayerController'/><category scheme='http://www.blogger.com/atom/ns#' term='m4v'/><category scheme='http://www.blogger.com/atom/ns#' term='simulator'/><category scheme='http://www.blogger.com/atom/ns#' term='preload'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: MPMoviePlayerController preload issues</title><content type='html'>As of this writing, the MPMoviePlayerController object doesn't seem to send the MPMoviePlayerContentPreloadDidFinishNotification notification on the iPhone Simulator. This is happening when I'm loading an .m4v over the net. This issue makes my app appear broken on the simulator, because I'm waiting for the preload to finish before calling the "play" function on the MPMoviePlayerController object. When I test on the iPhone itself, there's no problem. Just an FYI.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-7898984310129519898?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/7898984310129519898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/02/iphone-mpmovieplayercontroller-issues.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/7898984310129519898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/7898984310129519898'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/02/iphone-mpmovieplayercontroller-issues.html' title='iPhone: MPMoviePlayerController preload issues'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-6828537991060062450</id><published>2009-01-30T15:24:00.000-07:00</published><updated>2009-01-30T15:27:50.183-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uiimageview'/><category scheme='http://www.blogger.com/atom/ns#' term='rotate'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Rotate a UIImageView</title><content type='html'>Here's a simple little snippet that's useful if you want to rotate a UIImageView continuously for something like a clock hand graphic:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)&lt;br /&gt;&lt;br /&gt;CGAffineTransform cgCTM = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(45));&lt;br /&gt;myImage.transform = cgCTM;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-6828537991060062450?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/6828537991060062450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-rotate-uiimageview.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6828537991060062450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/6828537991060062450'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-rotate-uiimageview.html' title='iPhone: Rotate a UIImageView'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5636737894758116222</id><published>2009-01-30T11:29:00.003-07:00</published><updated>2010-05-04T18:07:15.919-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='custom font'/><category scheme='http://www.blogger.com/atom/ns#' term='truetype'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='ttf'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Custom font loading : complete example</title><content type='html'>&lt;b&gt;UPDATE: It looks like someone has built a far more robust custom font engine than my example here. I haven't tried it yet, but the example project looks great: &lt;a href="http://github.com/zynga/FontLabel"&gt;http://github.com/zynga/FontLabel&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This code was cobbled together from a couple different posts I found on blogs and iphone forums, &lt;a href="http://forums.macrumors.com/archive/index.php/t-569311.html"&gt;here&lt;/a&gt; and &lt;a href="http://silverity.livejournal.com/26436.html"&gt;here&lt;/a&gt;. This is a complete example, which nobody wanted to supply - I hope this is useful to someone. The one major hole is that is does not support multi-line text. Let me know if you figure out a good way to handle it :)&lt;br /&gt;&lt;br /&gt;I'm just going to post my 2 classes here. I've set up a base class that does the drawing, and a subclass that defines font-specific configuration. You'll have to put your .ttf (TrueType) font in the bundle, and use it's name there to customize your own font subclass. You'll also have to set the glyph offset in the subclass - a font-editing tool can help with this.&lt;br /&gt;&lt;br /&gt;Here we go:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;CustomFontBase.h&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;@interface CustomFontBase : UIView {&lt;br /&gt;NSMutableString *curText;&lt;br /&gt;UIColor *fontColor;&lt;br /&gt;UIColor *bgColor;&lt;br /&gt;int fontSize;&lt;br /&gt;NSString *fontName;&lt;br /&gt;NSString *fontExtension;&lt;br /&gt;float autoSizeWidth;&lt;br /&gt;int glyphOffset;&lt;br /&gt;BOOL isGlowing;&lt;br /&gt;UIColor *glowColor;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void)updateText:(NSString*)newText;&lt;br /&gt;- (void)initTextWithSize:(float)size color:(UIColor*)color bgColor:(UIColor*)bgColor;&lt;br /&gt;- (void)setGlow:(BOOL)glowing withColor:(UIColor*)color;&lt;br /&gt;- (void)autoSizeWidthNow;&lt;br /&gt;&lt;br /&gt;@property (nonatomic, retain) NSMutableString *curText;&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;CustomFontBase.m&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;#import "CustomFontBase.h"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@implementation CustomFontBase&lt;br /&gt;&lt;br /&gt;@synthesize curText;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (id)initWithFrame:(CGRect)frame {&lt;br /&gt;if (self = [super initWithFrame:frame]) {&lt;br /&gt;// set defaults&lt;br /&gt;[self setBackgroundColor:[UIColor clearColor]];&lt;br /&gt;bgColor = [UIColor clearColor];&lt;br /&gt;[self setCurText: [[NSMutableString alloc] initWithString:@""] ];&lt;br /&gt;fontColor = [UIColor whiteColor];&lt;br /&gt;fontSize = 15;&lt;br /&gt;isGlowing = FALSE;&lt;br /&gt;[self setContentMode:UIViewContentModeTopLeft];  // make sure it doesn't scale/deform when setFrame is called &lt;br /&gt;}&lt;br /&gt;return self;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (void)drawRect:(CGRect)rect {&lt;br /&gt;// get context and flip for normal coordinates&lt;br /&gt;CGContextRef context =  UIGraphicsGetCurrentContext();&lt;br /&gt;CGContextTranslateCTM ( context, 0, self.bounds.size.height );&lt;br /&gt;CGContextScaleCTM ( context, 1.0, -1.0 );&lt;br /&gt;&lt;br /&gt;// Get the path to our custom font and create a data provider.&lt;br /&gt;NSString *fontPath = [[NSBundle mainBundle] pathForResource:fontName ofType:fontExtension];&lt;br /&gt;CGDataProviderRef fontDataProvider = CGDataProviderCreateWithFilename([fontPath UTF8String]);&lt;br /&gt;// Create the font with the data provider, then release the data provider.&lt;br /&gt;CGFontRef customFont = CGFontCreateWithDataProvider(fontDataProvider);&lt;br /&gt;CGDataProviderRelease(fontDataProvider); &lt;br /&gt;// Set the customFont to be the font used to draw.&lt;br /&gt;CGContextSetFont(context, customFont);&lt;br /&gt;&lt;br /&gt;// prepare characters for printing&lt;br /&gt;NSString *theText = [NSString stringWithString: curText];&lt;br /&gt;int length = [theText length];&lt;br /&gt;unichar chars[length];&lt;br /&gt;CGGlyph glyphs[length];&lt;br /&gt;[theText getCharacters:chars range:NSMakeRange(0, length)];&lt;br /&gt;&lt;br /&gt;// draw bg&lt;br /&gt;if( bgColor != [UIColor clearColor] )&lt;br /&gt;{&lt;br /&gt;CGRect bgRect = CGRectMake (0, 0, self.bounds.size.width, self.bounds.size.height);&lt;br /&gt;CGContextSetFillColorWithColor( context, bgColor.CGColor );&lt;br /&gt;CGContextFillRect( context, bgRect );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Set how the context draws the font, what color, how big.&lt;br /&gt;CGContextSetTextDrawingMode(context, kCGTextFill);&lt;br /&gt;CGContextSetFillColorWithColor(context, fontColor.CGColor );&lt;br /&gt;CGContextSetFontSize(context, fontSize);&lt;br /&gt;&lt;br /&gt;// set a glow?&lt;br /&gt;if( isGlowing ) {&lt;br /&gt;//CGContextSetShadow(context, CGSizeMake(0,0), 3 );&lt;br /&gt;CGContextSetShadowWithColor( context, CGSizeMake(0,0), 3, glowColor.CGColor );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Loop through the entire length of the text.&lt;br /&gt;for (int i = 0; i &lt; length; ++i) {&lt;br /&gt;// Store each letter in a Glyph and subtract the MagicNumber to get appropriate value.&lt;br /&gt;glyphs[i] = [theText characterAtIndex:i] + glyphOffset;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// draw the glyphs&lt;br /&gt;CGContextShowGlyphsAtPoint( context, 0, 0 + fontSize * .25, glyphs, length ); // hack the y-point to make sure it's not cut off below font baseline - this creates a perfect vertical fit&lt;br /&gt;&lt;br /&gt;// get width of text for autosizing the frame later (perhaps)&lt;br /&gt;CGPoint textEnd = CGContextGetTextPosition( context ); &lt;br /&gt;autoSizeWidth = textEnd.x;&lt;br /&gt;&lt;br /&gt;// clean up the font&lt;br /&gt;CGFontRelease( customFont );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// call this after creating the LandscapeText object to set the styling&lt;br /&gt;- (void)initTextWithSize:(float)size color:(UIColor*)color bgColor:(UIColor*)txtBgColor {&lt;br /&gt;// store font properties&lt;br /&gt;fontColor = color;&lt;br /&gt;fontSize = size;&lt;br /&gt;bgColor = txtBgColor;&lt;br /&gt;&lt;br /&gt;// autoscale height to font size&lt;br /&gt;[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, fontSize)];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// set new text to display&lt;br /&gt;- (void)updateText:(NSString*)newText {&lt;br /&gt;[self setCurText: [NSString stringWithString:newText] ];&lt;br /&gt;[self setNeedsDisplay];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void)setGlow:(BOOL)glowing withColor:(UIColor*)color {&lt;br /&gt;glowColor = color;&lt;br /&gt;isGlowing = glowing;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;- (void)autoSizeWidthNow {&lt;br /&gt;//printf( "autoSizeWidth = %f \n", autoSizeWidth );&lt;br /&gt;[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, autoSizeWidth, fontSize)];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (void)dealloc {&lt;br /&gt;[curText release];&lt;br /&gt;[super dealloc];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;CustomFontMyFont.h&lt;/span&gt;&lt;pre&gt;#import &lt;UIKit/UIKit.h&gt;&lt;br /&gt;#import "CustomFontBase.h"&lt;br /&gt;&lt;br /&gt;@interface CustomFontMyFont : CustomFontBase {&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;CustomFontMyFont.m&lt;/span&gt;&lt;pre&gt;#import "CustomFontMyFont.h"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@implementation CustomFontMyFont&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (id)initWithFrame:(CGRect)frame {&lt;br /&gt;if (self = [super initWithFrame:frame]) {&lt;br /&gt;// Initialization code&lt;br /&gt;fontName = @"MyFont";&lt;br /&gt;fontExtension = @"ttf";&lt;br /&gt;glyphOffset = -29;        // adjust this offset per font until it prints the proper characters&lt;br /&gt;}&lt;br /&gt;return self;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;- (void)dealloc {&lt;br /&gt;[super dealloc];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight:bold;"&gt;Usage:&lt;/span&gt;&lt;pre&gt;CustomFontMyFont *myLabel = [[[CustomFontMyFont alloc] initWithFrame:CGRectMake(100, 100, 55, 20)] autorelease];&lt;br /&gt;[myLabel initTextWithSize:11 color:[UIColor whiteColor] bgColor:[UIColor clearColor]];&lt;br /&gt;[myLabel updateText:@"Custom Font"];&lt;br /&gt;[self addSubview:myLabel];&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5636737894758116222?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5636737894758116222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-custom-font-loading-complete.html#comment-form' title='30 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5636737894758116222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5636737894758116222'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-custom-font-loading-complete.html' title='iPhone: Custom font loading : complete example'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>30</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5317516759233717547</id><published>2009-01-29T18:16:00.000-07:00</published><updated>2009-01-30T11:03:58.312-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='addsubview'/><category scheme='http://www.blogger.com/atom/ns#' term='uiview'/><category scheme='http://www.blogger.com/atom/ns#' term='static'/><category scheme='http://www.blogger.com/atom/ns#' term='uiimageview'/><category scheme='http://www.blogger.com/atom/ns#' term='attach'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Attach an image with one line of code</title><content type='html'>I got sick of the 4 lines of code it takes to attach and garbage collect a UIImageView to your UIView, so I wrote a static function for our DisplayUtil class to clean up this process. Check it out below and feel free to use:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+ (UIImageView*)attachImageToView:(UIView*)viewObject withId:(NSString*)imgId andRect:(CGRect)rect {&lt;br /&gt; UIImageView *img = [[UIImageView alloc] initWithFrame:rect];&lt;br /&gt; img.image = [UIImage imageNamed:imgId];&lt;br /&gt; [viewObject addSubview:img];&lt;br /&gt; [img release];&lt;br /&gt; return img;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5317516759233717547?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5317516759233717547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-attach-image-with-one-line-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5317516759233717547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5317516759233717547'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-attach-image-with-one-line-of.html' title='iPhone: Attach an image with one line of code'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1637387919720274797</id><published>2009-01-27T13:21:00.000-07:00</published><updated>2009-01-27T13:29:41.285-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='graphic'/><category scheme='http://www.blogger.com/atom/ns#' term='block'/><category scheme='http://www.blogger.com/atom/ns#' term='click'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><category scheme='http://www.blogger.com/atom/ns#' term='displayobject'/><category scheme='http://www.blogger.com/atom/ns#' term='button'/><title type='text'>ActionScript 3: Prevent graphics from blocking your button</title><content type='html'>In Flash 9, a non-button graphic that lays over a real button wil prevent the user from clicking the button underneath. This was never a problem in Flash before AS3 / Flash 9, but is quite a common problem to deal with. It's quite easy to get around the issue. You simply need to disable any mouse interaction with the inactive graphic. Even though you haven't told it to act as a button, the default is to capture mouse actions as a DisplayObject. Just add this code to the non-button graphic:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;graphic.mouseChildren = false;&lt;br /&gt;graphic.mouseEnabled = false;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Fixed!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1637387919720274797?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1637387919720274797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/actionscript-3-prevent-graphics-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1637387919720274797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1637387919720274797'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/actionscript-3-prevent-graphics-from.html' title='ActionScript 3: Prevent graphics from blocking your button'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2217550374298160967</id><published>2009-01-21T14:50:00.000-07:00</published><updated>2009-01-21T14:54:22.636-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='screen'/><category scheme='http://www.blogger.com/atom/ns#' term='dim'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='dimming'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: Disable screen dimming</title><content type='html'>This can be very handy if you're developing an iPhone game, where the screen shouldn't automatically dim to save battery life. Use this code when you launch your gameplay view, and set it back when you leave gameplay:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[[UIApplication sharedApplication] setIdleTimerDisabled:YES];&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2217550374298160967?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2217550374298160967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-disable-screen-dimming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2217550374298160967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2217550374298160967'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-disable-screen-dimming.html' title='iPhone: Disable screen dimming'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-4316014600321110519</id><published>2009-01-19T15:32:00.000-07:00</published><updated>2009-01-29T18:30:22.445-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='notification'/><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='nsnotification'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>iPhone: send and receive events/notifications</title><content type='html'>Objective-C has a really friendly and useful event system that allows your objects to talk to each other without any knowledge of the other objects. Events are called Notifications in Objective-C, and are routed through a system-wide object called NSNotificationCenter. You don't need to import this object - it's always available to every class.&lt;br /&gt;&lt;br /&gt;Here's the syntax for dispatching an event/notification with an ID of "EventName":&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[[NSNotificationCenter defaultCenter] postNotificationName:"EventName" object:self];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It also sends along "self", which is a reference to the dispatching object. You could replace "self" with a reference to another object that may contain more relevant data to the event being dispatched.&lt;br /&gt;&lt;br /&gt;To respond to this event, you need to set up a listener:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listenerFunction:) name:@"EventName" object:nil];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Our object, "self" is now ready to receive this event. It must have a function called "listenerFunction", but this name is up to you. Note that setting "nil" as the object lets us respond to any object in the application that sends out a notification called "EventName". Alternatively, we can listen to only one object that will send this event, by replacing "nil" with a reference to the object.&lt;br /&gt;&lt;br /&gt;Finally, you need a function that actually does something when the event/notification is received. See below:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;- (void)listenerFunction:(NSNotification *)notification&lt;br /&gt;{&lt;br /&gt; MyDispactherObject *incomingObject = [notification object];&lt;br /&gt; NSLog(@"EVENT RECEIVED");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If we don't need to do anything with the object that was sent with the event, we can ignore the first line in the function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;[UPDATE]&lt;/span&gt;: Thanks to CC in the comment section for correcting my example and reminding us that we want to clean up after ourselves and remove event listeners before things are properly garbage collected. Here's the syntax for removing the listener we added above (replace "nil" with the object reference if you were listening to a specific object):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[[NSNotificationCenter defaultCenter] removeObserver:self name:@"EventName" object:nil];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, here's Apple's official Notification documentation for further reading:&lt;br /&gt;&lt;a href="http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html"&gt;http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-4316014600321110519?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/4316014600321110519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-send-and-receive.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4316014600321110519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/4316014600321110519'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-send-and-receive.html' title='iPhone: send and receive events/notifications'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-7506875951877863382</id><published>2009-01-16T09:16:00.000-07:00</published><updated>2009-01-16T09:24:38.028-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='as3'/><category scheme='http://www.blogger.com/atom/ns#' term='random number'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 2'/><category scheme='http://www.blogger.com/atom/ns#' term='as2'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript'/><category scheme='http://www.blogger.com/atom/ns#' term='actionscript 3'/><title type='text'>ActionScript: Random number function</title><content type='html'>I saw that one of the top results for "actionscript random number" in a Google search is incorrect, so I figured it would be a good idea to post another proper one.&lt;br /&gt;&lt;br /&gt;Here's the ActionScript 3 version:&lt;br /&gt;&lt;pre&gt;function randNum( low:int, high:int ):int&lt;br /&gt;{&lt;br /&gt; return Math.round( Math.random() * (high - low) ) + low;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;And here's the ActionScript 2 version:&lt;br /&gt;&lt;pre&gt;function randNum( low:Number, high:Number ):Number&lt;br /&gt;{&lt;br /&gt; return Math.round( Math.random() * (high - low) ) + low;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-7506875951877863382?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/7506875951877863382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/actionscript-random-number-function.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/7506875951877863382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/7506875951877863382'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/actionscript-random-number-function.html' title='ActionScript: Random number function'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-5056866010515342258</id><published>2009-01-15T09:25:00.000-07:00</published><updated>2009-01-15T09:40:11.396-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='function'/><category scheme='http://www.blogger.com/atom/ns#' term='setinterval'/><category scheme='http://www.blogger.com/atom/ns#' term='timer'/><title type='text'>Javascript: setInterval() - call a function every X seconds</title><content type='html'>setInterval() is used when you want a function to run repeatedly on a timer. I wrote this little html page to remind me to get up and stretch every half-hour. I keep it open in my browser during the day to keep me from slouching for too long. Programming for hours on end can lead to Repetitive Strain Injuries in the hands and arms (amongst other problems), so this could help you too :)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;setInterval ( "tellMeToGetUp()", 1000 * 60 * 30 );&lt;br /&gt;function tellMeToGetUp()&lt;br /&gt;{&lt;br /&gt; alert('GET UP DUDE!');&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;Note the time passed into the setInterval function. It means: 1000 milliseconds x 60 seconds x 30 minutes. setInterval uses milliseconds, so this is a clear way to describe how long you want the interval to be.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-5056866010515342258?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/5056866010515342258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/javascript-setinterval-call-function.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5056866010515342258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/5056866010515342258'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/javascript-setinterval-call-function.html' title='Javascript: setInterval() - call a function every X seconds'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-1817282886413968308</id><published>2009-01-14T16:51:00.000-07:00</published><updated>2009-01-14T16:59:17.416-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uiview'/><category scheme='http://www.blogger.com/atom/ns#' term='rotate'/><category scheme='http://www.blogger.com/atom/ns#' term='landscape'/><category scheme='http://www.blogger.com/atom/ns#' term='subview'/><title type='text'>iPhone: Rotate a sub view to landscape layout</title><content type='html'>After trying some other hacks, I came up with this little bit of code to rotate my full-screen UIView to landscape mode, which let me lay out all the sub views in a standard coordinate system. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)&lt;br /&gt;&lt;br /&gt;- (id)initWithFrame:(CGRect)frame {&lt;br /&gt; if (self = [super initWithFrame:frame]) {&lt;br /&gt;  // Initialization code&lt;br /&gt;  self.backgroundColor = [UIColor clearColor];&lt;br /&gt;  [self setViewToLandscape:self];&lt;br /&gt; }&lt;br /&gt; return self;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;-(void)setViewToLandscape:(UIView*)viewObject {&lt;br /&gt; [viewObject setCenter:CGPointMake(160, 240)];&lt;br /&gt; CGAffineTransform cgCTM = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-90));&lt;br /&gt; viewObject.transform = cgCTM;&lt;br /&gt; viewObject.bounds = CGRectMake(0, 0, 480, 320);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-1817282886413968308?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/1817282886413968308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-rotate-sub-view-to-landscape.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1817282886413968308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/1817282886413968308'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-rotate-sub-view-to-landscape.html' title='iPhone: Rotate a sub view to landscape layout'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2958672488424357502</id><published>2009-01-13T09:47:00.000-07:00</published><updated>2009-01-13T10:35:18.665-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uibutton'/><category scheme='http://www.blogger.com/atom/ns#' term='uiview'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='style'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><category scheme='http://www.blogger.com/atom/ns#' term='button'/><title type='text'>iPhone: Create a UIButton with a custom graphic</title><content type='html'>Here's a little code snippet if you don't want to use the standard UIButton styles. You can attach an image instead:&lt;br /&gt;&lt;pre&gt;UIButton *button = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame:CGRectMake(0, 0, 24, 24)];&lt;br /&gt;[button addTarget:self action:@selector(prevButtonClick:) forControlEvents:UIControlEventTouchUpInside];&lt;br /&gt;[button setBackgroundImage:[UIImage imageNamed:@"IntroArrowLeft.png"] forState:UIControlStateNormal];&lt;br /&gt;[self addSubview:button];&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2958672488424357502?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2958672488424357502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-create-uibutton-with-custom.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2958672488424357502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2958672488424357502'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-create-uibutton-with-custom.html' title='iPhone: Create a UIButton with a custom graphic'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3911337215074644290.post-2314194778143161258</id><published>2009-01-12T14:34:00.001-07:00</published><updated>2009-01-12T15:45:34.458-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='uibutton'/><category scheme='http://www.blogger.com/atom/ns#' term='uiview'/><category scheme='http://www.blogger.com/atom/ns#' term='touch'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>iPhone: Create a UIButton and respond to the touch</title><content type='html'>Here's the basic code to create a text button and do something when it's touched:&lt;br /&gt;&lt;br /&gt;&lt;pre style="overflow: auto;"&gt;// add the button to the view&lt;br /&gt;-(void)buildButton {&lt;br /&gt; UIButton *button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] initWithFrame:CGRectMake(0, 0, 150, 25)];&lt;br /&gt; [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];&lt;br /&gt; [button setTitle:@"CLICK IT" forState:UIControlStateNormal];&lt;br /&gt; [button setCenter:CGPointMake( 320 / 2, 480 - 25 )];&lt;br /&gt; [self addSubview:button];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// respond to the button click&lt;br /&gt;-(void)buttonClick:(UIView*)clickedButton&lt;br /&gt;{&lt;br /&gt; NSLog(@"CLICK!");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3911337215074644290-2314194778143161258?l=uihacker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://uihacker.blogspot.com/feeds/2314194778143161258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-create-uibutton-and-respond-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2314194778143161258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3911337215074644290/posts/default/2314194778143161258'/><link rel='alternate' type='text/html' href='http://uihacker.blogspot.com/2009/01/iphone-create-uibutton-and-respond-to.html' title='iPhone: Create a UIButton and respond to the touch'/><author><name>Justin</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
