Archive for the ‘Web Technologies’ Category

SVG Animations

I decided to play around a bit with animating SVG content. There are actually multiple ways to animate SVG: CSS (transition, transform, @keyframes), Javascript, or Synchronized Multimedia Integration Language (SMIL). Where possible, I tend to prefer Javascript, as you have far more flexibility compared to markup languages; however, out of curiosity, I did try my hand at SMIL as well.

Method 1: Javascript

Here’s the SVG markup for the object being animated.

<svg version="1.1" x="0px" y="0px" width="74px" height="74px" viewBox="-1.751 -1.751 74 74" enable-background="new -1.751 -1.751 74 74" xml:space="preserve">
    <
g id="circularMarker" transform="rotate(0 35.163 35.521)">                
        <
path fill="#27AAE1" d="M46.336,7.908c2.174,0.678,4.236,1.538,6.199,2.54V3.69c-1.417-0.607-2.875-1.146-4.377-1.616
            C37.794-1.161,27.147-0.491,17.793,3.242v6.663C26.41,5.825,36.518,4.843,46.336,7.908z"/>
        <
path fill="#27AAE1" d="M62.423,46.338c-0.679,2.173-1.537,4.236-2.538,6.199h6.757c0.605-1.417,1.147-2.877,1.615-4.382
            c3.235-10.364,2.564-21.006-1.167-30.362h-6.664C64.505,26.41,65.489,36.52,62.423,46.338z"/>
        <
path fill="#27AAE1" d="M23.992,62.42c-2.171-0.678-4.236-1.536-6.199-2.538v6.759c1.418,0.604,2.877,1.146,4.381,1.616
            c10.364,3.233,21.009,2.564,30.362-1.17v-6.664C43.921,64.505,33.81,65.488,23.992,62.42z"/>
        <
path fill="#27AAE1" d="M7.909,23.994c0.678-2.174,1.538-4.237,2.538-6.2H3.691c-0.606,1.416-1.147,2.878-1.617,4.38
            c-3.234,10.364-2.564,21.012,1.168,30.365h6.664C5.825,43.921,4.843,33.813,7.909,23.994z"/>
        <
circle fill="#00AEEF" cx="35.163" cy="35.521" r="11.331"/>
    </
g>
</
svg>    

To animate, the transform attribute on the #circularMarker group element is updated every frame to do a simple rotation at a rate of 0.275 deg/ms. You can see the result in the iframe below.

Here’s the Javascript code that makes it happen:

<script src="jquery-1.8.2.min.js" type="text/javascript"></script>
<
script type="text/javascript">

// setup window.requestAnimationFrame
(function ()
{
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
                                 window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();


// set initial frame time (in milliseconds)
var ft1 = new Date().getTime();

// set initial angle (in degrees)
var angleDeg = 0;

// function to rotate circle
function rotateCircularMarker()
{
var ft = new Date().getTime();
var ftDelta = ft - ft1;
ft1 = ft;

// rotate at a rate of 0.275 deg/ms
angleDeg += ftDelta * 0.275;

if (angleDeg >= 360) {
// full circle!, reset angleDeg
angleDeg = 0;
}

// transform the #circularMarker group
// Note: the rotation is about the center of the circle element (35.163, 35.521)
$('#circularMarker').attr('transform', 'rotate(' + angleDeg + ' 35.163 35.521)');

// call requestAnimationFrame to continue animating
requestAnimationFrame(rotateCircularMarker);
}

$(document).ready(
function ()
{

rotateCircularMarker();

});
            
</script>

Note that window.requestAnimationFrame is used, so a modern browser is required. For older browsers it is possible to use window.setInterval as a fallback.

Method 2: SMIL

With SMIL, the SVG code remains the same, with the exception of an animateTransform tag within the #circularMarker group element.

<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0 35.163 35.521" to="360 35.163 35.521" begin="0s" dur="1.336996s" repeatCount="indefinite"/>

The attributes of animateTransform describe the animation, mainly type, from, to, begin, dur, and repeatCount.

Obviously SMIL yields less code and removes all Javascript dependencies, but it does come at the cost of losing flexibility (as you can only perform transformations and timing operations supported by SMIL attributes) and having to learn yet another markup language.

jxNotify

I made a little JavaScript notification system, somewhat inspired by webOS and also by the type of notifications you see on Gmail.

jxNotify code

The central idea was to have an elegant system that could sensibly display the progress of AJAX operations; meaning notifications stays up while the operation is being done (i.e. while sending request and waiting for a reply from the server), then a success or failure message is posted upon completion, which fades away automatically.

While designed for AJAX calls, this could certainly be used in other cases as well.

jxNotify notifyPre

jxNotify notifyPostError


Initializing

// optional argument = icon, recommended size of 18x18
jxNotify.init('jx-notify.content/sdotspott-notify-icon.png');


Notify of operation in progress (notifyPre)

jxNotify.notifyPre('doing stuff...');


Notify of operation completed (notifyPost)

jxNotify.notifyPost('finished!');


Notify of operation failure (notifyPostError)

jxNotify.notifyPostError('something bad happened!');

 

Reflex Feedback 0.3

A small update to the Reflex Feedback Widget,

  • Design tweaks (border, box-shadow, border-radius on textarea; padding-top on copyright)
  • widgetPos argument added to init(), valid values => ‘left’, ‘right’

reflex feedback widget 0.3

So you can now position the widget on the right edge of the page like this:

Reflex.init($('body'), 'controller/post_feedback.php', 'right');

More info about the widget itself can be found in the original blog post.

dotspott public pages

New feature added to dotspott earlier this week: you can now create a public URL for any of your spotts, which will generate a page that looks something like the following,

dotspott public page, 63 bites

… and is accessible to anyone on the web.

Currently this can only be done from the web client:

  • Login
  • Click “Share…” on the submenu for the spott you want to make a link for
  • Click the “Make Public” button; the spott will be made public and the URL will appear

Note: All spotts are private by default; they can only be seen by you when you login or by someone with whom you’ve shared the spott info via email.

Edit: I should mention this is a proof of concept of Unity. There are actually no async calls beyond those for Google Maps.

Reflex Feedback 0.2

An updated version of the Reflex Feedback widget is now up.

Changes:

  • New icons done by myself and released under the same license as the code; no longer using the ones by Yusuke Kamiyamane. This should also make it easier for those who want to do custom modifications as they don’t have to worry about an attribution requirement for the icons.
  • New menu layout and new buttons. Now using jQuery UI buttons for everything, which allows for compatibility with jQuery UI styling, ThemeRoller, etc.
  • CSS fixes to prevent some inherited styles from screwing up layout.

reflex feedback widget

For info on how to use the widget, see my original post on Reflex Feedback.

NYC yum yum

NYC yum yum is my web app for the NYC Big Apps 2.0 competition.

NYC yum yum

It’s a very simple app for quickly finding restaurants by cusine + location. For each resturaunt, it shows the restaurant inspection grade, to give you an idea of how clean and safe the food at the establishment is, and also pulls the Yelp star rating to give you and idea of how good the food is.

NYC yum yum front page

NYC yum yum results

Search by cuisine and location (specifically, neighborhood) I felt was really important. Searching by name is, of course, much simpler, but when it comes to finding a new restaurant your likely not to know the name beforehand. Even if you have been to the restaurant before, unless it’s a regular spot for you, you’d likely still has issues remembering the name given the number of places to eat in New York City.

That said, this was far more difficult than I anticipated and I’m sad to say the current implementation is far from ideal. Here’s why:

  • The raw data set from the NYC Data Mine contains no geographic coordinates (latitude, longitude), so to get an accurate location, the address must be geocoded. There are a number of services to do this, but they’re all pretty limited. Google’s Geocoding API was my first choice, but I was wary of the terms of use,

    … the Geocoding API may only be used in conjunction with a Google map; geocoding results without displaying them on a map is prohibited. For complete details on allowed usage, consult the Maps API Terms of Service License Restrictions.

    My second choice was geocoder.us, but it had issues geocoding locations outside of Manhattan. So I put aside the idea of doing a geocode.
  • My next attempt was to do queries by neighborhood. Surely, it would be easy to translate between neighborhoods and zip codes, right?! Nope. All I could find were commercial services (e.g. maponics) that did it, and I wasn’t willing to go down that road.
  • My final attempt and what’s implemented, is grabbing the zip code from the the marker location on the google map. This sorta works. The problem is that the area covered by a zip code doesn’t necessarily match up exactly with a neighborhood’s boundary. So a restaurant that may not be shown in the search if it falls into an adjacent zip code.

My big disappointment is how restrictive and inaccessible all of this geographic data is, and the lack of such data severely compromises the effectiveness of the search.

Another, somewhat major issue with the raw data set is how restaurants are categorized. I’m noticing tons of establishments are simply identified with the cuisine type of “American.” For example, B Cup is a café in the East Village. If I was looking for it, I would search for “Café/Coffee/Tea” not “American.”

NYC yum yum

In fact, I think “American” is way to generic to describe any sort of cuisine.

In any case, NYC yum yum still works pretty well and does hit of the target of being able to find good, clean places to eat at, quick and easily. I’ll likely be working on improvements to it in the near future.

Edit: mixed up geocoding and reverse geocoding

dotspott photo markers

The dotspott web client has been updated yet again, this time I’ve added support for photo markers.

dotspott photo markers

Reflex Feedback widget

I worked on a small AJAX widget for user feedback built atop jQuery UI: Reflex Feedback. It’s inspired by the widgets you see from services like Get Satisfaction and UserVoice, but much simpler and it’s a frontend-only widget, how you handle the feedback info on the backend is up to you.

Here’s what it looks like.

reflex feedback widget dialog

And here’s what the tag that opens the dialog looks like:

reflex feedback widget tag

To use it, download or clone the ReflexFeedback repo from bitbucket

Place the .js file wherever you’d like but the /reflex.content folder should a subdirectory in the same folder as the page loading the .js file. Load reflex.js as you would any other javascript file:

<script type="text/javascript" src="js/reflex.js"></script>

Call Reflex.init() to add the widget to the page. The first argument is the DOM element to attach the additional HTML/CSS code to. The seconds argument is the server-side script to call when the user clicks Send Feedback.

Reflex.init($('body'), 'controller/post_feedback.php');

That’s it for the frontend. You should see the tag show up in the right-hand corner and when clicked the dialog open.

For the backend, the AJAX call to send the feedback info will send a POST request with 2 fields: feedback_type, feedback_txt.

Reflex expects an XML reply from the server:

<reflex>
<result>ok</result>
</reflex>

ok indicates a successful result, any other reply is considered an error.

A successful result will close the dialog and show another with a thank you message.

reflex feedback thank you dialog

For an error, a message is shown below the Send Feedback button, informing the user that an error has occurred and to try again.

reflex feedback send fail

As for what to actually do with the feedback, that’s up to you, but what I’m doing is sending myself an email with the feedback info. I’ve posted my PHP script below; feel free to use it, modify it, etc. If you do use this code, be sure to fill in your mail server credentials and a from address; you’ll also need PEAR’s Mail package installed.

<?php

require_once "Mail.php";
require_once "Mail/mime.php";

header('Content-type: application/xml; charset=utf-8');
echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";

if(!isset($_POST['feedback_type']) || !isset($_POST['feedback_txt']))
{
echo "<reflex><result>error:missing-arguments</result></reflex>";
}
else
{
$from = "...";
$to = "...";
$subject = "Feedback from user...";

$feedback_type = $_POST['feedback_type'];
$feedback_txt = $_POST['feedback_txt'];

$bodyHtml = "<html><body>";
$bodyHtml .= "<p>Type: {$feedback_type}</p>";
$bodyHtml .= "<p>Feedback: {$feedback_txt}</p>";
$bodyHtml .= "</body></html>";
$body = $bodyHtml;

$host = "...";
$port = "...";
$username = "...";
$password = "...";

$headers = array('MIME-Version' => '1.0rn',
'Content-type' => 'text/html; charset=utf-8',
'From' => $from, 'To' => $to, 'Subject' => $subject);


$smtp = Mail::factory('smtp',
array ('host' => $host,
'port' => $port,
'auth' => true,
'username' => $username,
'password' => $password));

$mail = $smtp->send($to, $headers, $body);

if (PEAR::isError($mail))
{
$err_details = $mail->getMessage();
echo "<reflex><result>error:send-failure</result><details>{$err_details}</details></reflex>";
}
else
{
echo "<reflex><result>ok</result></reflex>";
}
}

?>

That’s all for now. I’ll work on more features and options for customization in the future. You can see the widget in action over at dotspott.com

Local search on dotspott

Local search is now available on the dotspott web client; allowing you to search for local venues and add them to your list of spotts.

dotspott local search for cocoa bar

The Google Maps API v3, which is used by dotspott, doesn’t really allow for local search and the Local Search API itself is deprecated (however, as per Google’s deprecation policy, it should be available until Nov. 2013). What I did was use gmaps-api-v3-googlebar, which allows adding a google-bar like control to the map.

One interesting thing I needed to do that wasn’t directly possible with gmaps-api-v3-googlebar update a few other things after one of the search results were selected. I wanted to avoid touching the gmaps-api-v3-googlebar code, so I did this by getting a reference to the existing event handler, then overwriting it with a new function, which called the previous event handler function.

Here’s an example where we grab the reference to the existing selectResult event handler (searchResultPre), overwrite with a new event handler, call the previous handler (binding to window.gbar, the instance of window.jeremy.jGoogleBar; binding is necessary b/c the event handler references this internally), then add some new functionality where we modify a paragraph element in the DOM (id = map_position) to show the position of the local marker that is selected.

selectResultPre = window.jeremy.jGoogleBar.prototype['selectResult'];
window.jeremy.jGoogleBar.prototype[
'selectResult'] = function (result)
{
selectResultPre.call(window.gbar, result);

    
var searcher = window.jeremy.gLocalSearch.searchers[0];
    
var results = searcher['results'];
    
var lmarker = result['marker'];

    $(
'#map_position').text(lmarker.getPosition().toString());
}

oh, and yes, this is using jQuery; $(‘#map_position’) should have given it away.

@font-face

I’ve always played it safe with fonts when it comes to web design, sticking to fonts commonly available across operating systems such as Verdana, Tahoma, Trebuchet MS, etc. However, I’m pretty psyched to see how well the CSS @font-face attribute is supported. Format support is somewhat of a mess: EOT for Internet Explorer and TTF/OTF for WebKit-based browsers (Chrome, Safari). However, Firefox 3.6+ supports the new Web Open Font Format, which is poised to become the new standard and will, hopefully, quickly find it’s way into the other browsers.

If your in Firefox, Safari, or Chrome, here’s a font I’ve loved for a while, Titillium:

TitilliumText999wt

I’ve never really had problems finding fonts for free or even commercial use, but Font Squirrel now makes the whole search process dead simple and super easy. They also seem to have a pretty awesome converter; though I used this oft2woff converter for my little demo above.