view mbp.js @ 44:9c7c3cb5f776

simplified cropping logic
author Atul Varma <varmaa@toolness.com>
date Mon, 14 Dec 2009 11:33:35 -0800
parents 1909896414d8
children
line wrap: on
line source

$(window).ready(
  function() {
    var containerWidth = $("#container").width();
    var rectRegexp = /rect\((\d+),? (\d+),? (\d+),? (\d+)\)/;

    function dWidth(element) {
      return parseInt($(element).attr("data-width"));
    }

    // Each entry may have multiple resolutions of the same image;
    // choose the one that's best for our display device, and
    // make sure we have a cropping area for its thumbnail.
    $(".mbp-entry").each(
      function() {
        var pictures = $(this).find(".picture");
        var lastCrop = null;
        var best = null;
        pictures.each(
          function() {
            var crop = $(this).attr("data-crop");
            if (crop)
              lastCrop = this;
            if (best) {
              // The "best" image is the lowest-resolution image
              // that's still bigger than the width of our container:
              // this way we never upscale, but we also don't waste
              // bandwidth getting a massive image that we won't
              // see.
              if (dWidth(this) < dWidth(best) &&
                  dWidth(this) >= containerWidth) {
                best = this;
              }
            } else
              best = this;
          });

        var cropAttr = $(best).attr("data-crop");
        var scaling = 1;

        // If our best picture doesn't have a cropping rect associated
        // with it, we'll use the scaled cropping rect of another
        // resolution.
        if (!cropAttr && lastCrop) {
          cropAttr = $(lastCrop).attr("data-crop");
          scaling = dWidth(best) / dWidth(lastCrop);
        }

        if (!cropAttr)
          throw new Error("No 'data-crop' for " + best.href);

        var parts = cropAttr.match(rectRegexp);
        if (!parts)
          throw new Error("Invalid 'data-crop' for " + best.href);

        var crop = {top: Math.floor(parts[1] * scaling),
                    right: Math.floor(parts[2] * scaling),
                    bottom: Math.floor(parts[3] * scaling),
                    left: Math.floor(parts[4] * scaling)};

        var image = $("<img/>");
        image.attr("src", best.href);
        image.attr("width", $(best).attr("data-width"));
        image.attr("height", $(best).attr("data-height"));
        image.data("crop-parts", crop);
        $(this).find(".link").empty().append(image);
        pictures.remove();
      });

    var images = $(".mbp-entry img");
    var loadsLeft = images.length;

    // Create the thumbnails and attach event handlers to them.
    images.each(
      function() {
        function onLoaded() {
          $("#countdown").text(--loadsLeft);

          var crop = $(this).data("crop-parts");
          crop.width = crop.right - crop.left;
          crop.height = crop.bottom - crop.top;
          var canvas = document.createElement("canvas");
          var self = $(this.parentNode).clone();
          var maxWidth = Math.max($(document.body).width(), containerWidth);
          self.find("img").removeAttr("width")
                          .removeAttr("height")
                          .css({maxWidth: maxWidth});
          $(canvas).mouseenter(
            function() {
              $("#big-picture").empty();
              $("#big-picture").append(self);
            });
          $(canvas).addClass("thumbnail");
          $(this).before(canvas);
          var ctx = canvas.getContext("2d");
          ctx.drawImage(this,
                        crop.left,
                        crop.top,
                        crop.width,
                        crop.height,
                        0,
                        0,
                        canvas.width,
                        canvas.height);
          $(this).remove();
          if (loadsLeft == 0) {
            $("#countdown").remove();
            $("#container").fadeIn();
          }
        }

        if (this.complete)
          onLoaded.call(this);
        else
          this.addEventListener("load", onLoaded, false);
      });

    $("h1").mouseover(
      function() {
        $("#big-picture").empty();
      });

    $("#countdown").text(loadsLeft);
  });