Autoscale, center an image with overlaid elements

The Problem

I recently had an interesting web layout problem.  I needed show a picture in the center of an area on the screen.  That’s normally pretty easy, but I also had a few extra requirements:

  1. The image should expand proportionately to cover as much of the stage as possible.
  2. The image should not scale any larger than a given size.
  3. I needed to overlay elements on top of the image (a hotspot in my case) that scales proportionately and retains the same relative location.

At first glance the answer would be to use some absolute or relative positioning and use a background-image with the background-size:cover (at least in modern browsers).  I did need to support IE7, which hurt that approach, but the requirement to overlay an element and scale it was also an issue.  When using background-size:cover, the element isn’t forced to stay proportional, just the image maintains proportions.  I needed to keep the actual element proportional too or I wouldn’t know where to put the overlaid element.

The Layout Approach

The answer does require some JavaScript, but CSS can get us halfway.  Here is the layout we need:

layout

HTML

So let’s set up the HTML (we won’t worry about the footer – just leave space for it:

<div id="stage"> <div id="imageHolder"> <img src="SomeImage.jpg" />

<div id="hotspot"></div> </div> </div>

CSS

The approach in CSS is to get the stage filling its area using absolute positioning. 

#stage { position:absolute; top:0px; bottom:38px; right:0px; left:0px; padding:0; background-color:Black; }

The imageHolder is also set to use absolute positioning and has its max-width and max-height set to the size/proportion we want, but the actual positioning will be done in JavaScript.

#imageHolder {
    position:absolute;
    max-height:720px;
    max-width:920px;     
}

And the image and placeholder are setup for absolute positioning.  The image is styled to fill the stage, and the hotspot is styled using percentages for position and size so that it will scale with the image:

#imageHolder img { position:absolute; top:0px; left:0px; min-height:100%; width:100%; height:auto; } #imageHolder #hotspot { position:absolute; cursor:pointer;

top:22.1%;

left:50.5%;

width:44%;height:42.3% }

JavaScript

We create a resize function that will recompute how big the imageHolder should be and where it should be placed.

function resize() {
    //Get stage size (less any desired padding)
    var stage = $('#stage');
    var div = $('#imageHolder');
    var newHeight = stage.height() - 10;
    var newWidth = stage.width() - 10;
    

    //Constrain to proportioon
    var proportion = parseInt(div.css('max-height')) / parseInt(div.css('max-width'));
    if (newWidth > newHeight / proportion) {
        newWidth = newHeight / proportion;
    }
    if (newHeight > newWidth * proportion) {
        newHeight = newWidth * proportion;
    }

    //Set the height and width -- the max-height/width will contrain this
    div.width(newWidth);
    div.height(newHeight);

    //Center it
    div.css({
        "left": (stage.width() - div.width()) / 2 + "px",
        "top": (stage.height() - div.height()) / 2 + "px"
    });
}

And then when we load the page we just need to call the resize function and setup the window’s resize event to call it as well.

$(document).ready(function () { $(window).resize(function () { resize(); });

 

resize(); });

See it in Action

You can see this in action on JSFiddle at http://jsfiddle.net/tYY87/  (I just made a few changes there for the smaller screen size.)

JavaScript Developer Position at Unboxed Technology

Senior JavaScript Developer

Unboxed Technology is looking for a JavaScript developer to create exciting applications to be used on a mobile platform. Unboxed is a company that excels in developing interactive tools to help companies train their employees and sell products to their customers. These tools are used online, in stores, and on mobile devices.

The Senior JavaScript Developer will help build interactive training modules that will be used on handheld devices. The modules will be written as web pages and installed via PhoneGap for disconnected use. The emphasis for this project will be on stand-alone mobile web development with occasional web service calls when connected.

Required skills:

· JavaScript

· HTML

· CSS

· JQuery (including animation)

· JSON service calls

· MySQL database and SQL queries

· Experience creating rich web pages with interactivity, animation, and media

Preferred skills:

· HTML 5 experience

· CSS 3 experience

· Tailoring UI for iPad/WebKit browsers

· PhoneGap

· Basic animation

· Multiple JavaScript frameworks

· Source code control

· Working with geographically dispersed teams

This is initially a 2-3 month contract with strong potential for follow-up work or a full-time position.  Applicants can be in Richmond, Virginia or work remotely from the Portland, Oregon/Vancouver, Washington area.

Please include resume and any sample applications showing your own work. To validate the skills of the applicants, each will be asked to create a basic sample program that should take just a few hours to complete.

If interested, please e-mail talent@unboxedtechnology.com

Javascript checking for file on different web site

I just had one of those “shouldn’t this be easier” moments.  I had some client-side Javascript that needed to do something different based on whether or not a file existed on another website (basically to choose what URL to pass to the Flash Player).  Server-side coding was not an option; I just had an HTML file to work with.  I thought it would be easy…but then I didn’t consider the cross-domain scripting security in the browsers!

I tried a few options:

  1. Using XMLHttpRequest to check for the existence of a file – this would be the cleanest way if the file was in the same domain as the HTML file, but XMLHttpRequest is usually blocked for cross domain calls. It worked on IE8 if the setting “Access data sources across domains” was enabled, but did not work in IE7 or Firefox
  2. Using an IFRAME on the page and communicate via URL fragments – this is a complicated trick that sites like Facebook use to address similar issues. The coding is complex, however, and can have impact on the Back button and things. (See http://msdn.microsoft.com/en-us/library/bb735305.aspx or http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication)
  3. Using JSON calls to a service on the second server – browser security does allow calls to a web service on a different domain, but this would require putting code on that second server.  This was not an option.

So I had to resort to a little less elegant approach, but one that requires minimal scripting and works across browsers.  Nothing prevents us from pulling an image from another website, so we can place a 1×1 transparent gif on the other website as a “marker” for the file we are looking for.  Then we simply put the img tag on our page and respond to the onload and onerror events.

<img src='http://otherwebsite.com/marker.gif' onload='DoIfItsThere();' onerror='DoIfItsNotThere();' style='visibility:hidden' />

While placing a marker file on other websites may not always be an option, this approach could be used to check whether that site is available.  Want to see if Google is running?  Just pull down the Google logo and if it works, it’s working!  (Yes, bad example because Google has web services we could call.  But you get the point)