The time has come for me to pack my bags and move south. I've been in Pittsburgh, PA since I graduated from Edinboro University in 2003, and even a few years before college. Living and working in the burgh, I've gained a lot of experience and had the pleasure working with many really talented people. But, alas, the weather has finally gotten to my wife and me. Plus, my son is starting 2nd grade in the fall! and I fear that if we don't move soon, we'll never leave.
I was offered an Interactive Developer role with a big New York company called Infusion. Infusion is opening an office in Raleigh, NC and I'll be part of the many new hires for that team.
It saddens me to leave my current role with Moxie and move out of the city I've grown to love (and hate sometimes), but this is a great opportunity and I have to give it a try. Raleigh is a really pretty city and the area is booming with a lot of tech jobs, so we'll see how it goes... and hey, you can always move back, right?
Wednesday, June 4, 2014
Thursday, May 8, 2014
Date Strings from Twitter & Facebook Invaild? (IE & Safari)
Just learned about this yesterday. It seems that if you pass the date string that is returned from Twitter and/or Facebook to the javascript Date() constructor, in IE (and Safari), it shows it as an invalid date.
Twitter returns the "created_time" as something like this: Thu May 01 13:57:04 +0000 2014, which is shown as "Invalid Date" in IE.
For Facebook, the 'created_time' value is something like: 2014-04-17T12:59:04+0000, which is shown as "Invalid Date" in IE and Safari.
So, what fixed the problem, for now, was to do a little manipulation on the date string before it is passed it to the Date() constructor.
Twitter returns the "created_time" as something like this: Thu May 01 13:57:04 +0000 2014, which is shown as "Invalid Date" in IE.
//created_time = Thu May 01 13:57:04 +0000 2014
var date = new Date( jsonData.created_time );
console.log( date.toString() );
// = IE 9 & 10: 'Invalid Date'
// = Chrome: 'Mon May 05 2014 14:50:00 GMT-0400 (Eastern Daylight Time)'
// = FireFox: 'Mon May 05 2014 14:50:00 GMT-0400 (Eastern Standard Time)'
// = Safari: 'Mon May 05 2014 14:50:00 GMT-0400 (Eastern Daylight Time)'
For Facebook, the 'created_time' value is something like: 2014-04-17T12:59:04+0000, which is shown as "Invalid Date" in IE and Safari.
//created_time = 2014-04-17T12:59:04+0000
var date = new Date( jsonData.created_time );
console.log( date.toString() );
// = IE 9 & 10: 'Invalid Date'
// = Chrome: 'Thu Apr 17 2014 08:59:04 GMT-0400 (Eastern Daylight Time)'
// = FireFox: 'Thu Apr 17 2014 08:59:04 GMT-0400 (Eastern Standard Time)'
// = Safari: 'Invalid Date'
So, what fixed the problem, for now, was to do a little manipulation on the date string before it is passed it to the Date() constructor.
//twitter = 'Thu May 01 13:57:04 +0000 2014'
//facebook = '2014-04-17T12:59:04+0000'
var created = facebook.created_time;
if( isFacebook )
{
//this fixes the issue in IE and Safari, and still works in Firefox and Chrome even though they don't need it.
created = created.replace(/-/g, '/').replace(/T/, ' ').replace(/\+/, ' +');
}
else if( isTwitter )
{
//this is only an issue in IE, so we can just do a quick test and fix the issue.
if( navigator.userAgent.match(/MSIE\s([^;]*)/) )
created = created .replace(/( \+)/, ' UTC$1');
}
var date = new Date( created );
Monday, May 5, 2014
Moving my SVG Animation to Canvas with EaselJS (follow-up post)
This is a follow-up to the previous post titled "SVG Animation With Clip Paths and Linear Gradients".
I was able you port the SVG animation over to the <canvas /> using EaselJS. It wasn't too bad, I was having a lot of trouble converting the SVG path data that was exported from illustrator, but that all changed when my co-worker found this site: http://www.professorcloud.com/svg-to-canvas/.
Here is the code I ended up with that re-created the animation from before:
I was able you port the SVG animation over to the <canvas /> using EaselJS. It wasn't too bad, I was having a lot of trouble converting the SVG path data that was exported from illustrator, but that all changed when my co-worker found this site: http://www.professorcloud.com/svg-to-canvas/.
Here is the code I ended up with that re-created the animation from before:
function initCanvasHeart(canvasId)
{
var stage = new createjs.Stage(canvasId),
goldRect = new createjs.Shape(),
greenRect = new createjs.Shape(),
blueRect = new createjs.Shape(),
goldMsk = new createjs.Shape(),
greenMsk = new createjs.Shape(),
blueMsk = new createjs.Shape(),
aa = new createjs.Shape(),
width = stage.canvas.width,
height = stage.canvas.height,
rectWidth = width / 0.4;
//create gold rect
goldRect.graphics
.beginLinearGradientFill(
["#FFC423", "#ffe191", "#FFC423"],
[0.4, 0.5, 0.6], 0, 0, rectWidth, 0)
.drawRect(0, 0, rectWidth, height);
goldRect.x = width-rectWidth;
goldRect.cache(0,0,rectWidth, height);
//add it to the canvas
stage.addChild(goldRect);
//create gold rect mask
drawGoldStrip( goldMsk.graphics.beginFill("#000000") );
goldRect.mask = goldMsk;
//create green rect
greenRect.graphics
.beginLinearGradientFill(
["#6EB43F", "#b6d99f", "#6EB43F"],
[0.4, 0.5, 0.6], 0, 0, rectWidth, 0)
.drawRect(0, 0, rectWidth, height);
greenRect.x = width-rectWidth;
greenRect.cache(0,0,rectWidth, height);
//add it to the canvas
stage.addChild(greenRect);
//create green rect mask
drawGreenStrip( greenMsk.graphics.beginFill("#000000") );
greenRect.mask = greenMsk;
//create blue rect
blueRect.graphics
.beginLinearGradientFill(
["#0083C8", "#7fc1e3", "#0083C8"],
[0.4, 0.5, 0.6], 0, 0, rectWidth, 0)
.drawRect(0, 0, rectWidth, height);
blueRect.x = width-rectWidth;
blueRect.cache(0,0,rectWidth, height);
//add it to the canvas
stage.addChild(blueRect);
//create blue rect mask
drawBlueStrip( blueMsk.graphics.beginFill("#000000") );
blueRect.mask = blueMsk;
//add a layer to fix anti-aliasing in Chrome
//- the mask in chrome was really pixelated compared to Firefox
aa.graphics.setStrokeStyle(1, 1, 1, 2);
drawGreenStrip( aa.graphics.beginStroke("#6EB43F") ).endStroke();
drawGoldStrip( aa.graphics.beginStroke("#FFC423") ).endStroke();
drawBlueStrip( aa.graphics.beginStroke("#0083C8") ).endStroke();
aa.cache(0, 0, width, height);
stage.addChild(aa);
//add animations
//using TweenJS that is part of EaselJS, we can create a simple repeating animation
createjs.Tween.get(goldRect, {loop:true}).to({x: 0 }, 8000);
createjs.Tween.get(greenRect, {loop:true}).to({x: 0 }, 8000);
createjs.Tween.get(blueRect, {loop:true}).to({x: 0 }, 8000);
//add an event listener to the internal ticker object to update the stage,
//otherwise we won't see the animation
createjs.Ticker.addEventListener("tick", function( evt )
{
stage.update();
});
}
//these method were each generated by:
//http://www.professorcloud.com/svg-to-canvas/
function drawGreenStrip(g)
{
g.moveTo(72.603,317.736);
g.bezierCurveTo(71.87,316.727,74.997,320.537,72.603,317.736);
g.bezierCurveTo(63.166,306.699,37.833999999999996,281.177,25.986999999999995,258.153);
g.bezierCurveTo(-0.2700000000000067,207.12500000000003,-12.807000000000002,128.69500000000002,18.386999999999993,68.50900000000001);
g.bezierCurveTo(38.157,30.357,72.942,6.779,118.972,0.328);
g.bezierCurveTo(122.661,0.096,126.004,0,129.237,0);
g.bezierCurveTo(180.874,0,240.743,26.183,251.61399999999998,145.724);
g.lineTo(251.61399999999998,145.724); g.bezierCurveTo(224.38899999999998,88.70599999999999,175.11599999999999,64.73599999999999,124.02599999999998,79.07799999999999);
g.bezierCurveTo(96.53399999999998,86.79299999999999,72.37499999999997,114.35999999999999,60.29699999999998,146.654);
g.bezierCurveTo(42.154,195.165,42.749,259.684,72.603,317.736);
g.lineTo(72.603,317.736);
g.closePath();
return g;
}
function drawGoldStrip(g)
{
g.moveTo(446.57,41.168);
g.bezierCurveTo(423.02,17.616,391.671,4.649,358.286,4.649);
g.bezierCurveTo(310.154,4.649,265.962,31.224,249.12099999999998,69.678);
g.bezierCurveTo(253.90999999999997,82.536,257.52799999999996,97.475,259.68199999999996,114.699);
g.bezierCurveTo(279.698,91.652,307.98499999999996,77.94200000000001,335.94599999999997,77.94200000000001);
g.bezierCurveTo(358.849,77.94200000000001,379.186,87.218,391.736,103.39500000000001);
g.bezierCurveTo(407.001,123.06200000000001,410.514,151.238,401.897,184.871);
g.bezierCurveTo(389.59499999999997,232.871,326.669,325.246,243.46599999999998,359.457);
g.bezierCurveTo(244.652,359.401,276.452,359.675,295.70399999999995,354.659);
g.bezierCurveTo(372.371,334.659,441.4409999999999,277.092,459.236,242.862);
g.bezierCurveTo(490.488,182.738,503.576,98.174,446.57,41.168);
g.closePath();
return g;
}
function drawBlueStrip(g)
{
g.moveTo(239.213,444.16);
g.bezierCurveTo(218.941,444.16,205.017,435.036,187.38,423.485);
g.bezierCurveTo(183.989,421.265,180.448,418.94100000000003,176.668,416.56);
g.bezierCurveTo(152.79000000000002,401.536,106.22800000000001,355.632,96.757,342.354);
g.bezierCurveTo(67.397,301.205,44.056000000000004,186.868,72.796,146.81599999999997);
g.lineTo(79.569,137.36399999999998);
g.lineTo(80.349,148.96899999999997);
g.bezierCurveTo(83.259,192.36699999999996,93.43100000000001,212.12199999999996,111.904,247.97699999999998);
g.bezierCurveTo(137.74599999999998,298.144,195.71699999999998,360.70899999999995,248.362,371.56399999999996);
g.bezierCurveTo(307.151,369.43199999999996,356.589,351.84,428.28700000000003,299.106);
g.lineTo(428.28700000000003,299.106);
g.bezierCurveTo(401.58700000000005,335.235,329.206,400.438,291.47900000000004,424.78499999999997);
g.bezierCurveTo(277.495,433.81,258.921,444.16,239.213,444.16);
g.closePath();
return g;
}
SVG Animation With Clip Paths and Linear Gradients
One of our clients decided to update their logo from a circle to more of a heart. Currently, on the about us page of their website, they have a large version of their logo that spins slowly and when you rollover (or swipe/tap) each color in the logo information appears describing their products. One of our designers and I, sat down to discuss what we could do with a heart shaped logo because having it spin looked weird. We finally came up with a subtle shine effect on the colors, which at first, I thought would be easy since I've done it before with flash. I came to find out that there was a little more to it then I originally thought.
I decided to try the animation with SVG. After reading up on SVG graphics and animations, came up with the following which turned out great:
Now, if you can see the animation (more on that in a sec), what is happening is that I have 3 wide <rect /> tags each with a <linearGradient /> set as there fill. Each rectangle has an <animation /> tag that slowly animates it from left to right and then repeats. I also have 3 <clipPaths /> tags that each contain a <path /> tag whose "d" attribute is a bunch of draw commands I exported from illustrator. This is one of my first times working with SVG graphics and I really enjoyed it. I can't wait until it is more widely supported because it reminds me of Flex and MXML.
That last sentence about it being more widely supported is where I am now. I have a backup image setup as a fallback for users whose browsers don't support SVG, ClipPath, and SMIL animations, but the account managers are a little concerned that the client is going to be upset since we made a big deal about this.
So, today I'm going to revisit one of the ideas of using the canvas to draw this animation. It's a bit more supported right now, but before, I was having trouble getting the vector drawing correct since each part of the logo is an irregular shape. I'm thinking either using EaselJS (since I've used it before) or maybe FabricJS (since I think it might be more popular).
I decided to try the animation with SVG. After reading up on SVG graphics and animations, came up with the following which turned out great:
Now, if you can see the animation (more on that in a sec), what is happening is that I have 3 wide <rect /> tags each with a <linearGradient /> set as there fill. Each rectangle has an <animation /> tag that slowly animates it from left to right and then repeats. I also have 3 <clipPaths /> tags that each contain a <path /> tag whose "d" attribute is a bunch of draw commands I exported from illustrator. This is one of my first times working with SVG graphics and I really enjoyed it. I can't wait until it is more widely supported because it reminds me of Flex and MXML.
That last sentence about it being more widely supported is where I am now. I have a backup image setup as a fallback for users whose browsers don't support SVG, ClipPath, and SMIL animations, but the account managers are a little concerned that the client is going to be upset since we made a big deal about this.
So, today I'm going to revisit one of the ideas of using the canvas to draw this animation. It's a bit more supported right now, but before, I was having trouble getting the vector drawing correct since each part of the logo is an irregular shape. I'm thinking either using EaselJS (since I've used it before) or maybe FabricJS (since I think it might be more popular).
Wednesday, April 16, 2014
Combining PHP template files with associative array models
I've been using Codeigniter for the past 2 years now and I really like it. It might just be the MVC (like) pattern, but it's got a lot of nice built in classes that make building website in PHP a lot quicker, easier and cleaner. So, with my recent exposure to Wordpress, I came to a spot where I was mixing a lot of html with php code, which is something I really hate doing.
Thinking of how, with Codeigniter (and other frameworks), you can combine a *.php template with a data array (or a view model) and render a page I was curious. How does Codeigniter load a php page into a scope with the variables from the supplied data array and spit out the resulting page? After doing a bit of digging I found this nifty function that I ported to my Wordpress theme and now my code looks much cleaner.
Thinking of how, with Codeigniter (and other frameworks), you can combine a *.php template with a data array (or a view model) and render a page I was curious. How does Codeigniter load a php page into a scope with the variables from the supplied data array and spit out the resulting page? After doing a bit of digging I found this nifty function that I ported to my Wordpress theme and now my code looks much cleaner.
function load_template($filename, $data=array())
{
$filename = '/inc/templates/' . $filename . '.php';
if (is_file($filename))
{
extract($data);
ob_start();
include( $filename );
$buffer = ob_get_contents();
@ob_end_clean();
return $buffer;
}
return false;
}
Now with this function you can write a template like...
//inc/templates/biocard.php
<div class="card">
<div class="photo">
<?php if( ! empty($image) ) : ?>
<img src="<?= $image; ?>" alt="<?= $name; ?>" />
<?php else : ?>
<img src="/img/missing-user-image.jpg" alt="<?= $name; ?>" />
<?php endif; ?>
</div>
<div class="detail">
<h4><?= $name; ?></h4>
<h5><?= $title; ?></h5>
<?php if( ! empty($email) ) : ?>
<a class="email" href="mailto:<?= strtolower($email); ?>">Email</a>
<?php endif; ?>
</div>
</div>
... and populate it with an associative array:
$model = array(
'name' => 'Jason',
'title' => 'Web Developer',
'email' => 'jason@home.com',
'image' => 'path/to/profile/image.jpg'
);
return load_template('biocard', $model);
Wednesday, March 12, 2014
How to get the Twitter tweets for a screen name using Application-only OAuth (PHP & cURL)
For a recent project, the designers had a sidebar that displayed the 5 most recent tweets from the client's twitter account. I was surprised to find out it's not as easy as it used to be. Twitter now requires you to use OAuth to display tweets from a certain account or hashtag.
If you ever come across a project like this, hopefully these steps below will help you out.
Step 1: You'll need to create a Twitter application to get an API key and secret which will allow you to make API request.
Step 2: We'll start with the back end PHP code to make this work. These code examples are from an ajax callback in Wordpress, but you should be able to fit it into your project as needed. WARN: your API key and secret should not be visible on your site so don't put them in your javascript files.
First, we take the key and secret and create an access token out of them, then we can use the access token to get an application bearer token from Twitter. The bearer token is what we will use to make all our API requests. The Twitter documentation for this can be found here: https://dev.twitter.com/docs/auth/application-only-auth
Step 3: Hopefully, success! You now have a bearer token which allows you to make application-only API requests to many of the different REST resources that Twitter offers: https://dev.twitter.com/docs/api/1.1.
If we continue with the code above, we can now access the /statuses/user_timeline.json resource to pull tweets for a specific screen name.
Step 4: On the front-end, we can use javascript via ajax to grab the json data from PHP and generate a list of tweets to be displayed on the webpage.
If you ever come across a project like this, hopefully these steps below will help you out.
Step 1: You'll need to create a Twitter application to get an API key and secret which will allow you to make API request.
- Go to: https://dev.twitter.com/ (make sure your logged in to twitter)
- In the upper right side of the header you should see your avatar pict and a dropdown menu arrow.
- Select "My Applications" from that dropdown and then click the "Create New App" button.
- Give Twitter all the details about what your app does and then click "Create your Twitter Application".
- Once your app is created, select it (if it's not already open) and select the tab at the top named "API Keys". This should show you your API key and API secret. Copy these two values, you will need them in the next steps.
Step 2: We'll start with the back end PHP code to make this work. These code examples are from an ajax callback in Wordpress, but you should be able to fit it into your project as needed. WARN: your API key and secret should not be visible on your site so don't put them in your javascript files.
First, we take the key and secret and create an access token out of them, then we can use the access token to get an application bearer token from Twitter. The bearer token is what we will use to make all our API requests. The Twitter documentation for this can be found here: https://dev.twitter.com/docs/auth/application-only-auth
add_action( 'wp_ajax_nopriv_twitter_tweets', 'twitter_tweets_callback' );
function twitter_tweets_callback()
{
//settings - example values
$api_key = 'xvz1evFS4wEEPTGEFPHBog';
$api_secret = 'L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg';
$access_token = base64_encode(urlencode($api_key) . ':' . urlencode($api_secret));
//connect to the twitter api and get bearer token
$bearer_token = get_bearer_token( $access_token );
//---
//search for recent tweets for the client (method below)
$tweets_json = get_user_timeline($bearer_token, '[client's screen name here]');
//echo resulting json
echo $tweets_json;
die(); // this is required to return a proper result
}
function get_bearer_token( $access_token )
{
$ch = curl_init( 'https://api.twitter.com/oauth2/token' );
$post_fields = array(
'grant_type' => 'client_credentials'
);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_fields));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Basic ' . $access_token,
'Content-Type: application/x-www-form-urlencoded;charset=UTF-8'
));
//send request
$response = json_decode( curl_exec($ch) );
curl_close($ch);
return $response->access_token;
}
Step 3: Hopefully, success! You now have a bearer token which allows you to make application-only API requests to many of the different REST resources that Twitter offers: https://dev.twitter.com/docs/api/1.1.
If we continue with the code above, we can now access the /statuses/user_timeline.json resource to pull tweets for a specific screen name.
//make a GET request using the Bearer token to access tweets for a screen name
function get_user_timeline( $bearer_token, $screen_name )
{
$url = 'https://api.twitter.com/1.1/statuses/user_timeline.json';
$fields = array(
'screen_name' => $screen_name,
'count' => 5,
'exclude_replies'=> 1
);
$ch = curl_init( $url . '?' . http_build_query($fields) );
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer ' . $bearer_token
));
//send request
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
Step 4: On the front-end, we can use javascript via ajax to grab the json data from PHP and generate a list of tweets to be displayed on the webpage.
var itemTmpl = [
'<li>',
'<span class="name"><strong>${name}</strong> @NPCpgh</span>',
'<span class="desc">${text}</span>',
'<span class="date">${date}</span>',
'</li>'
].join('\n');
$.post('/wp-admin/admin-ajax.php', { action: 'twitter_tweets' }, function(response)
{
//turn json array of object into html array and join
var html = $(json).map(function(index, item)
{
return itemTmpl.replace('${name}', item.user.name)
.replace('${text}', item.text);
.replace('${date}', item.created_at );
}).toArray()
.join('\n');
//update display list
$(".results").html( html );
}, 'json');
Friday, March 7, 2014
Introducing grunt-namespacer Task
Grunt has caught my eye, again, as a nice way to "build" all my javascript into a small, clean file that I can include in the websites I work on.
With the Grunt setup complete on the Wordpress site/theme I am working on, I started looking for a way to concat, closure wrap, and compress/obfuscate all the JavaScript in my source folder so I can separate out my scripts into different files (kinda like how a bunch of node.js projects work). I figured, at the most, this would be nice for utility functions that I could copy from site to site with minimal code editing.
My searches on GitHub lead me to the following tasks: grunt-contrib-concat, grunt-wrap, grunt-contrib-uglify. But, after setting up these tasks and doing some test builds, I started thinking that it would be nice if there was a task that would create namespaces automatically to avoid method name collisions. The only task I could find that was close was grunt-autowrap but it didn't do exactly what I wanted. This lead me into looking at how to build your own grunt tasks.
This is what I ended up with: grunt-namespacer.
This task will take your javascript files and concat and closure wrap them based on your folder structure.
For example, if your folder structure in your js folder is like this:
Then after you run the namespacer task you will get a file named 'app.js' (base folder name), and be able to access everything like this:
Also, scope is based on folder so any function in tabs.js can access methods in forms.js without having to use the namespace.
This task is free to use and I welcome any comments to help improve it.
later,
-Jason
With the Grunt setup complete on the Wordpress site/theme I am working on, I started looking for a way to concat, closure wrap, and compress/obfuscate all the JavaScript in my source folder so I can separate out my scripts into different files (kinda like how a bunch of node.js projects work). I figured, at the most, this would be nice for utility functions that I could copy from site to site with minimal code editing.
My searches on GitHub lead me to the following tasks: grunt-contrib-concat, grunt-wrap, grunt-contrib-uglify. But, after setting up these tasks and doing some test builds, I started thinking that it would be nice if there was a task that would create namespaces automatically to avoid method name collisions. The only task I could find that was close was grunt-autowrap but it didn't do exactly what I wanted. This lead me into looking at how to build your own grunt tasks.
This is what I ended up with: grunt-namespacer.
//Gruntfile.js
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
//grunt-namespacer task config
namespacer : {
basic : {
src: 'js/src/app/',
dest: 'js/build/'
}
}
...
});
// Load the plugins for all tasks.
grunt.loadNpmTasks('grunt-namespacer');
// Default task(s).
grunt.registerTask('default', ['namespacer']);
This task will take your javascript files and concat and closure wrap them based on your folder structure.
For example, if your folder structure in your js folder is like this:
+ src/
+ app/
init.js
+ controls/
checkbox.js
tabs.js
forms.js
+ models/
person.js
cart.js
+ utils/
empty.js
json.js
ajax.js
Then after you run the namespacer task you will get a file named 'app.js' (base folder name), and be able to access everything like this:
app.init.run();
var person = new app.models.Person('Dave');
app.utils.ajax('/register', person, function(response)
{
person.id = response.data.id;
});
Also, scope is based on folder so any function in tabs.js can access methods in forms.js without having to use the namespace.
This task is free to use and I welcome any comments to help improve it.
later,
-Jason
Subscribe to:
Posts (Atom)