Personal and Professional Blog of Rich Hauck

Displaying the last Twitter Tweet in your webpage

May 18, 2012

I was just looking for an easy way to integrate the last tweet/current status of a Twitter user in a web page without any heavy plugins, widgets, or embedded tweets.

I was rather surprised how difficult it proved finding a simple example online.

It could, of course, be my laziness in navigating Twitter’s developer API, but Twitter clearly has updated their API over the years, and there’s a lot of deprecated examples out there.From the looks of it, Twitter API now utilizes ids with each tweet, which makes sense. If you’re wondering where you can find the id of a tweet, it can easily be found in the source code of a feed page.

The tweet id is stored as an HTML5 -data attribute in any twitter.com feed page

To add the last tweet, let’s start with some simple HTML:

<p>@mandalatv's last tweet: <a id="status" href="#"></a></p>
<ul>
	<li><a id="favorite" href="#">Favorite</a></li>
	<li><a id="reply" href="#">Reply</a></li>
	<li><a id="retweet" href="#">Retweet</a></li>
</ul>

You can call Twitter’s API from your own page by including the following script call (replacing out my Twitter username, of course):

<script src="http://twitter.com/statuses/user_timeline/mandalatv.json?callback=getLastTweet&count=1"></script>

You’ll notice I’ve tacked on a callback argument in the query. This defines the JavaScript function I want to handle Twitter’s API response. Here’s the callback’s definition:


function getLastTweet(tweets) {
	lastTweet = tweets[0];
	var status = document.getElementById('status');
	status.innerHTML = lastTweet.text;
	status.href = 'http://twitter.com/mandalatv/status/' + lastTweet.id;

	var retweet = document.getElementById('retweet');
	retweet.href = 'http://twitter.com/intent/retweet?tweet_id=' + lastTweet.id;

	var reply = document.getElementById('reply');
	reply.href = 'http://twitter.com/intent/tweet?in_reply_to=' + lastTweet.id;

	var favorite = document.getElementById('favorite');
	favorite.href= 'https://twitter.com/intent/favorite?tweet_id=' + lastTweet.id;
}

Basically, this callback gets the last tweet object in the array (tweets[0]) and inserts its text property into <a id=”status” href=”#”></a>. The object also has an id, which we use to create and assign links to the retweet, reply, and favorite links.

Note that I include these scripts after the HTML code. If they’re included beforehand, the JavaScript won’t know what HTML you’re referring to since it’ll load before the HTML (this, of course, could be handled with an event listener that listens for the page to complete loading).

Lastly, here’s a separate page with a simple last tweet example.

I hope this helps someone save some time!

BarCampHbg4: Animating With HTML 5

April 14, 2012

With how busy work’s been lately, I completely hashed together a presentation on animation in HTML5 during the beginning session of BarCamp Harrisburg 4. Despite this, as promised, I’m posting my examples from the event.

The examples are all linked as separate HTML pages below. To keep things simple across formats, the item animated is a simple red box with a black border.

I should introduce this by saying that “HTML5″ is really a horrible branding job, since it encompasses CSS3, HTML, Javascript, and several other technologies under one name. The “engine” behind animating is really Javascript, with the exception of CSS3 transitions, which we’ll get out of the way now.

CSS3 Transitions

View Animating in CSS3 example

In order to keep animating predictable in CSS, I’m animating an absolutely-positioned div with an id of #box. The initial CSS includes the following attributes (the example includes vendor-specific prefixes, but this is the heart of it):

transition:left 1s;
transition-timing-function:ease-out;

To trigger the animation, I’m calling the following:

div#wrapper:hover #box{
	left:450px;
}

Herein lies the issue with animating in CSS–it requires user input, as we’re triggering the animation by hovering over the container #wrapper box.

Some developers frown upon animation being managed by CSS instead of JavaScript. Personally, I can see how this might get messy, especially if you’re using JavaScript to manage other animations.

There’s a nice list of all CSS3 properties that can be animated on the w3′s site.

HTML Div

View Animated Div Example

To animate a <div>, we’re going to reuse the styles from the CSS example, however, we’re adding a bit of JavaScript into the mix. Notice we’re calling a window.addEventListener() in the <script> rather than putting some inline script into the tag itself (Yuck!).

window.addEventListener('load', init, false);
function init(){
	var wrapper = document.getElementById("wrapper");
	var box = document.getElementById("box");
	var count = 0;
	setInterval(loop, 30);

	function loop(){
		box.style.left = count + "px";

		// use offsetWidth since non-inline CSS values can't be easily calculated
		var max = parseInt(wrapper.offsetWidth);
		count+=10;
		if(count >= max){
			count = -50;
		}
	}
}

What this code does is call the init() function as soon as the window has loaded . We’re then telling the script to remember the #wrapper and #box divs. Then we call the almighty setInterval(), which calls accepts two arguments–the function it’s to continually call (“loop”) and how often it’s to call it (in thousandths of a second–in our case, 30). For more info, here is Mozilla’s writeup on setInterval.

In the loop(), we’re continually setting the div#box’s left CSS property. We’re also determining the div#wrapper’s width and using that to tell the animated div#box when it should reset it’s absolute position, thereby creating the appearance of the animation wrapping around.

Now’s a good time to mention window.requestAnimationFrame(), which is a more memory-conscientious alternative to setInterval(). I’m keeping my eye on it, but have avoided it for the time being, since it currently has low browser support.

SVG

View Animated SVG Example

The SVG example uses setInterval() too, however, we’re setting the position by calling

rect.setAttribute("x",count);

instead of constantly setting a CSS property. You’ll also notice that the SVG’s properties are all inline, which keeps with its XML roots.

Canvas

View Animation in Canvas Example

I suppose one of the advantages of SVG and HTML divs is that they are document objects, so they’re accessible with JavaScript’s document.getElementById(). Canvas can be accessed this way, too, however, the contents within <canvas> are created by script, so they’re not really part of the DOM. Here’s the script:

window.addEventListener('load', init, false);
function init(){
	var canvas = document.getElementById("canvas");
	var ctx = canvas.getContext("2d");
	var count = 0;
	const CANVAS_WIDTH = canvas.width;
	const CANVAS_HEIGHT = canvas.height;
	// size of our box
	var size = 50;

	// define which function we want to call and the interval (in milliseconds) to call it.
	setInterval(loop, 30);

	function loop() {
		// first, we clear the canvas to prevent trails
		clear();

		// set style
		ctx.fillStyle = "#f00";
		ctx.strokeStyle = '#000';
		ctx.lineWidth   = 5;

		// Draw box
		ctx.fillRect(count, 230, size, size);
		ctx.strokeRect(count, 230, size, size);

		// if count reaches the right side, set it back to the left.
		if(count >= CANVAS_WIDTH + size){
			count = -size;
		}
		count+=10;
	}
	/**
	* Clears the canvas
	*/
	function clear(){
		ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
	}
}

To draw to the canvas, you need to access it’s context, so we call

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

to access the 2D context (canvas has a 3D context, but I’ve yet to find a video card that supports it!).

Canvas “remembers” settings unless you tell it otherwise, so the fillStyle, strokeWidth, and lineWidth settings remain the same unless we tell the context otherwise. I’ve also added a clear() function, which basically clears the canvas before it redraws the box. Try removing this, and you’ll see that the canvas just continually writes overtop of itself.

Well, I hope this helps someone out, and I really hope that I’ll have time to prepare a better presentation with slides for next year. :P

Categories: canvas, HTML5, javascript, webdesign
Tags:

Another Year, Another Harrisburg BarCamp

April 11, 2012

I was quite happy with the turnout this year, which appeared to be a good mix of new and returning attendees (Okay, so we probably had more new attendees, considering we clearly had our best turnout yet).

While we had 225 signups, and I really wish I knew how many honored those signups, if only to figure out how we had so many spare t-shirts!

Granted, other barcamps have registration tables that confirm attendance, but Harrisburg’s remains small enough that I don’t think it’s necessary. One attendee suggested charging for the event, even confessing to me that they’d easily pay $25 for a ticket. While I’m amused at how true it is (even a $1 fee amazingly invokes a psychological investment in people), we’re fortunate to have sponsors every year, and I’ve always felt that “free” is inherent to barcamp culture.

Next year, I hope to get more volunteers (as it’s usually a team of people that organize barcamps!). I thought the after party was a lot of fun, and it sounds like it may return for next year. We may shorten the schedule by a session to keep the momentum going.

Speaking of the schedule, posting it online via Google Docs worked well, despite it being a last-minute addition (granted, we had online schedules in the past, but it never received as much positive feedback). It’ll definitely be linked on the website for 2013. While I wish the schedule board could be placed in the lobby, the venue unfortunately can’t support it.

I’m hoping that next year more people jump to get on the board. It seems like there was even less of that in 2012 than there was in 2011, and I’d love it if we could get to the fervor that the 1000+ attendee strong BarCamp Philly seems to get.

Anyhow, hoping to see everyone again at Harrisburg University on April 6, 2013.

Categories: Harrisburg
Tags: , ,

The Rockville Bridge

March 22, 2012

I’ve probably seen hundreds of pictures of the Rockville Bridge thanks to Beyond Second, but I’d never actually shot it myself until last week.

I took some of my photography students down to Fort Hunter last Saturday as a field trip, and finally fired off a few shots. What was particularly cool was we ran into this rather unkempt, yet extremely friendly young man carrying a tripod and a video camera. I soon discovered he was a train enthusiast who’d come to shoot the train going over the bridge (apparently, he thought we were enthusiasts as well). I still haven’t found his work on YouTube, but I’m sure it’s up there amidst the sea of other videos.

Firefox Bug with context.scale() in HTML5 Canvas

March 5, 2012

While testing my last blog post, I discovered that my canvas exercise didn’t work in Firefox 10.0.2 Mac. There were no console errors, and the script worked fine in Safari and Chrome.

What I discovered was a really remote bug in Firefox regarding canvas and scaling. After a bunch of troubleshooting, I determined that scaling the context to 0 prevented the animation from drawing.

My workaround is simply to catch the size and reset it to a really low number, like 0.01.

ctx.save();
ctx.translate(this.x, this.y);

var size = (Math.round(_count*100)/100);

// Workaround for Firefox bug
if(size <= 0){
size = 0.01;
}

I immediately did a search after making the correction and came across this bug documentation on Mozilla’s site. I hope they fix it.

Categories: HTML5, javascript
Tags: , , ,

Flying X: Experimenting with OOP JavaScript

March 1, 2012
Flying X

Click the image above to see the Canvas example in action.

Several years ago I completed a Flash-based screensaver for an X-Games website (here’s the SWF example). I wanted to see how difficult it would be to recreate such an animation using HTML5 Canvas.

I started by creating a shape in Adobe Illustrator and using the excellent Ai->Canvas plugin. I then restructured the code as an object (Lee Brimlow has a great intro tutorial on OOP Javascript).

Now, one of the limitations with OOP Javascript versus ActionScript 3.0 is that JavaScript objects don’t inherit an addEventListener() method like Flash Objects do. I was tempted to write this from scratch, but fortunately came across this MIT-licensed JavaScript class that can manage custom events.

By basing my shape’s prototype off of this EventTarget class, I can dispatch and listen to events similar to how I would in Flash. Each X shape initializes with a maximum size, then, once it reaches that size, it dispatches an event, which in-turn triggers a reset() method that assigns a new max, along with a new random x and y position.

The last step I wanted to take was to use window.requestAnimationFrame() instead of setInterval() since it’s supposed to yield better performance. I ended up abandoning this, though, since it’s still in the experimental phase and doesn’t offer as much browser support.

UPDATE: I discovered a Firefox-specific bug related to scaling a canvas’s context to 0. I updated the code, and here’s my documentation.

Perlin Noise in HTML5 Canvas

January 31, 2012

I was experimenting with Perlin Noise for an underwater effect on a website. I posted the results here, since there doesn’t seem to be an example online of what I wanted.

Not surprisingly, I canned the idea, as it’s simply too processor-intensive for aesthetics. It made for an interesting exercise in canvas, though.

Coming from an ActionScript background, I really wish I better knew how the “offset” array was implemented in the ActionScript call, as it’s not a part of Perlin’s original class:

perlinNoise(baseX:Number, baseY:Number, numOctaves:uint, randomSeed:int, stitch:Boolean, fractalNoise:Boolean, channelOptions:uint = 7, grayScale:Boolean = false, offsets:Array = null):void
Generates a Perlin noise image.

Fortunately, I didn’t have to port the original code to JavaScript, as I found it on GitHub. In the ActionScript world, I’d increment the offset over time to create an organic-looking water effect. For HTML5 canvas, I found this could be replicated by incrementing the z argument (zOff) in “classical” noise:

var result = perlin.noise(xVal, yVal, zOff);

Here’s the result.

Categories: ActionScript, art, canvas, Flash, HTML5

Brownian Motion in HTML5 Canvas

January 20, 2012

Brownian Motion

Ya know, cause I couldn’t find it anywhere (Lovingly stolen from Processing documentation). View the example.

I’m hoping to convert Craig Reynolds’ Boids to JavaScript/Canvas at some point in the future, too.

window.addEventListener('load', init, false);
function init(){
	var canvas = document.getElementById("canvas");
	if (canvas.getContext('2d')){
  		main(canvas);
	} else {
    	console.log("Canvas tag is not supported");
	}
}
function main(canvas){
	var canvas = canvas;
	var ctx = canvas.getContext("2d");
	const CANVAS_WIDTH = canvas.width;
	const CANVAS_HEIGHT = canvas.height;

	var num = 10;
	var range = 200;

	var ax = [];
	var ay = [];

	for(var i = 0; i < num; i++) {
	  ax[i] = CANVAS_WIDTH/2;
	  ay[i] = CANVAS_HEIGHT/2;
	}

	setInterval(draw, 30);

	function draw(){
		// Shift all elements 1 place to the left
		  for(var i = 1; i < num; i++) {
		    ax[i-1] = ax[i];
		    ay[i-1] = ay[i];
		  }
		  // Put a new value at the end of the array
		  var r2x = range*2;
		  ax[num-1] += (Math.random()*r2x)-range;
		  ay[num-1] += (Math.random()*r2x)-range;

		  // Constrain all povars to the screen
		  ax[num-1] = constrain(ax[num-1], 0, CANVAS_WIDTH);
		  ay[num-1] = constrain(ay[num-1], 0, CANVAS_HEIGHT);

		  // Draw a line connecting the povars
		  for(var i = 1; i < num; i++) {

			var alpha = i/num;
			ctx.globalAlpha = i/num;

			ctx.moveTo(ax[i-1], ay[i-1]);
			ctx.lineTo(ax[i], ay[i]);
			ctx.stroke();
		  }
	}
	function constrain(val, min, max){
		if(val > max){
			val = max;
		}else if(val < min){
			val = min;
		}
		return val;
	}
}
Categories: canvas, HTML5

Working with HTML5 Range Input

January 17, 2012

View Example

I felt compelled to post this HTML5 range input example because I couldn’t find code online that didn’t rely on JQuery to output a value (not that I have anything against it, just that it can be overkill for simple things like this).

The code below outputs the value of the range to a nearby <span>. I created a “showOutput” function to make it easier to use with multiple inputs.

window.addEventListener('load', initSlider, false);
/**
* Initializes sliders
*/
function initSlider(){
	// get range input
	var myRange = document.getElementById("myRange");
	myRange.addEventListener('change', function(){showOutput(myRange, "rangeOuput")}, false);
	document.getElementById("rangeOuput").innerHTML = rangeOuput.value;

	// call range input on window init to display initial value
	showOutput(myRange, "rangeOuput");
	/**
	* Displays output to text fields.
	* @param slider		id of range input
	* @param field		id of span to write value.
	*/
	function showOutput(slider, field){
		document.getElementById(field).innerHTML = slider.value;
	}
}
Categories: HTML5, javascript

Revisiting Interactive Media

January 16, 2012
fibonacci

Playing around with the Fibonacci number in Canvas. Click image for example. Code below.

I recently read a CNN op-ed piece by my former instructor, Doug Rushkoff, on how coding should be taught in every school as a way to be more competitive in the global industry. I couldn’t agree more.

For the past two years I’ve taught an Interactive Media course at Harrisburg Area Community College that has traditionally been taught in Adobe Flash. This semester, I decided to revisit the medium in which to teach interactive media, especially now that web-based Flash is being replaced with web standards technology like HTML, CSS, and JavaScript.

I haven’t completely replaced Flash in the course, as it remains a valuable tool for complex animation, video, and games. I have, however, decided to begin with the fundamentals of programming, and feel that the Flash IDE has too many distractions to serve as the starting medium.

I gave a lot of thought towards Processing, provided it’s easy-to-approach IDE, its large community, and its excellent documentation. In the end, though, I decided on HTML5 Canvas, as my students will likely end up using javascript instead of Java.

To a more selfish end, it’s forced me to better grasp canvas and JavaScript. I purposely chose a medium I wanted to learn, as I’m already comfortable with Flash and doubt I will be revisiting Java.

I’m going to try and start posting more code, such as this for the Fibonacci example:

window.addEventListener('load', init, false);
var canvas;
/**
* Detects for context 2d
*/
function init(){
	canvas = document.getElementById("myCanvas");
	if (canvas.getContext('2d')){
  		main(canvas);
		initSliders();
	} else {
    	console.log("Canvas not supported");
	}
}
/**
* Initializes sliders
*/
function initSliders(){
	var radRange = document.getElementById("radRange");
	radRange.addEventListener('change', function(){showOutput(radRange, "rangeOuput")}, false);
	document.getElementById("rangeOuput").innerHTML = radRange.value;

	var distRange = document.getElementById("distRange");
	distRange.addEventListener('change',  function(){showOutput(distRange, "distOuput")}, false);
	document.getElementById("distOuput").innerHTML = distRange.value;

	/**
	* Displays output to text fields.
	* @param slider		id of range input
	* @param field		id of span to write value.
	*/
	function showOutput(slider, field){
		document.getElementById(field).innerHTML = slider.value;
	}
}
/**
* Main
* @param canvas target canvas
*/
function main(canvas){
	var ctx = canvas.getContext("2d");

	var max = 200; 						// number of items on screen
	var i = 0; 							// initialize for counter
	const fib = 1/1.618033989;			// Fibonacci Sequence
	var radius = 0; 					// initial radius
	var lastInputRadius;				// remembers previous state to determine if positioning needs changed
	var lastInputDistance;				// remembers previous state to determine if positioning needs changed

	var circles = [];		 			// Create Array to hold items

	const CANVAS_RIGHT = canvas.width;
	const CANVAS_BOTTOM = canvas.height;

	var interval = setInterval(draw, 30);

	/**
	* Draws pattern to screen
	*/
	function draw() {
		var inputRadius = document.getElementById("rangeOuput").innerHTML;
		var inputDistance = document.getElementById("distOuput").innerHTML;
		if(i < max){
			// create shape
			radius += inputRadius*fib;
			lastInputRadius = inputRadius;
			lastInputDistance = inputDistance;
		    var dist = i*inputDistance; //represents distance from object
		    var x = Math.cos(radius*Math.PI/180)*dist + CANVAS_RIGHT/2;
		    var y = Math.sin(radius*Math.PI/180)*dist + CANVAS_BOTTOM/2;
			var hex = rgbToHex(255-i,0,i);
		    circles[i] = new Circle(ctx, x, y, (i/max)*100, hex);
		    i++;
		}else{
			// if input has changed, reposition shape
			if(lastInputRadius != inputRadius || lastInputDistance != inputDistance){
				radius += inputRadius*fib;
				clear();
				for(var j = 0; j < max; j++){
					radius += inputRadius*fib;
				    var dist = j*inputDistance; //represents distance from object
				    var x = Math.cos(radius*Math.PI/180)*dist + CANVAS_RIGHT/2;
				    var y = Math.sin(radius*Math.PI/180)*dist + CANVAS_BOTTOM/2;
					var hex = rgbToHex(255-j,0,j);
					circles[j].render(x, y, (j/max)*100, hex);
				}
			}
		}
		lastInputRadius = inputRadius;
		lastInputDistance = inputDistance;
	}
	/**
	* Draws circle.
	*/
	function Circle(ctx, x, y, r, hex){
		this.ctx = ctx;
		this.centerX = x;
		this.centerY = y;
		this.radius = r;

		this.render = function render(x, y, r, hex){
			this.centerX = x;
			this.centerY = y;
			this.radius = r;

			this.ctx.beginPath();
			this.ctx.arc(this.centerX, this.centerY, this.radius, 0, 2*Math.PI, false);
			this.ctx.fillStyle = hex;
			this.ctx.fill();
			this.ctx.lineWidth = 2;
			this.ctx.strokeStyle = "black";
			this.ctx.stroke();
		}
		this.render(this.centerX, this.centerY, this.radius, hex);
	}
	/**
	* Converts RGB values to hexidecimal
	* @param r 0-255 red value
	* @param g 0-255 green value
	* @param b 0-255 blue value
	*/
	function rgbToHex(r, g, b) {
		/**
		* Converts numeric value to base-16
		* @param c		target value
		*/
		function componentToHex(c) {
		    var hex = c.toString(16);
		    return hex.length == 1 ? "0" + hex : hex;
		}

	    return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
	}
	/**
	* Clears the canvas
	*/
	function clear(){
		ctx.clearRect(0, 0, CANVAS_RIGHT, CANVAS_BOTTOM);
	}
}

It’s been difficult not having a definitive API documentation like ActionScript and Processing have. The best I’ve found so far has been HTML5 Canvas Tutorials accompanied by a lot of O’Reilly JavaScript books. Coming from an ActionScript background, I’m still wrapping my head on how every function is an object, and how privatization, and event listening isn’t quite so baked in. I’m know the code above could be optimized more–eliminating globals, calculating x and y-positions once in draw(), etc., but it’s just a sketch.

I haven’t quite figured out how to structure my experiments on this blog, but my goal this year is posting more content, and spending less time examining distractions and vices.

Categories: canvas, HTML5, webdesign

About Me

Rich HauckI'm a designer, developer, and teacher based in Harrisburg, Pa. I run Hauck Interactive, Inc.




Archives