jQSlickWrap

the pixel-perfect prose plugin

v0.2

need to wrap content around an image? ...really around an image?

jQSlickWrap is a plugin for jQuery which enables you to easily and accurately wrap your text around the content of floated images.

It's as simple as $('img').slickWrap();

download it! contribute!

About

Image showing paragraph difference between normal wrapping and SlickWrapping

Why would I need this?

If you've ever felt the need to wrap stuff around an irregularly-shaped image using CSS's float, you may have been somewhat disappointed to find out that it's forced to wrap around the image's bounding box, rather than the actual contents of the image.

What's the best part?

It's really easy to use! Check out some of the examples for ideas...

Tell me about what it can do...

What browsers does it work on?

jQSlickWrap requires that your browser support HTML 5's <canvas> element, and in particular it needs to have support for the toDataURL() function on canvases (meaning it won't work with excanvas, for now). jQSlickWrap is known to work on the following browsers:

If you happen to know that it works on additional browsers, let me know on twitter.

How does it work?

Man with a shovel.

Not interested in the nitty gritty low down on how jQSlickWrap works its "magic"? Skip ahead to the examples.

As stated in the features list above, jQSlickWrap implements a client-side version of the Sliced and Diced Sandbags method of wrapping text around an irregularly-shaped object (all bundled in a nice tidy jQuery plugin, of course).

To do this, it needs to have access to the individual pixels of the images it's operating on -- which is why for jQSlickWrap to work, you need to have a browser that supports HTML 5's new <canvas> element.

Here's an overview of the algorithm:

  1. If necessary, pre-load the image.
  2. Determine the CSS styles for the image (float and padding).
  3. Create a <canvas> element and set its dimensions to the size of the image plus its padding.
  4. Draw the image onto the canvas in the top-left location.
  5. Figure out the "background" color of the image by examining the pixel data at the top-left corner of the image.
  6. Fill the <canvas> with this background color.
  7. Re-draw the image contents onto the <canvas>, but now in the correct location as specified by its padding.
  8. Iterate through the image to find the "edge" of the image's contents at each row - save this width. (the size of a row is defined to be the resolution in the settings to a call to slickWrap).
  9. Using the widths collected in the previous step, generate <div> elements of those sizes.
  10. Float the <div>s to the correct side, and set their clear style to the same side.
  11. Set the background-image to a non-repeating image described by a call to canvas.toDataURL() for the original's containing element.
  12. Hide the original image.

Examples

Example 1 - Basic SlickWrapping

All you need to SlickWrap your images is to call the slickWrap function on the results of a jQuery query:

<html>
    <head>
        <title>jQSlickWrap Demo 1</title>
        <script src="./jquery-1.3.2.min.js" type="text/javascript"></script>
        <script src="./jquery.slickwrap.js" type="text/javascript"></script>
        <style type="text/css">
            .wrapReady {
                float: left;
            }
        </style>
        <script type="text/javascript" charset="UTF-8">
            $(document).ready(function(){
                $('.wrapReady').slickWrap();
            });
        </script>
    </head>
    <body>
        <img src="./myImage.jpg" class="wrapReady" />
        <p>Lots of text goes here..</p>
    </body>
</html>

See it in action here!

Note: the images selected by the query should have some sort of float styling applied to them. Either float: right or float: left

Example 2 - SlickWrapping With Style

jQSlickWrap is capable of figuring out what kind of padding you want to use when you SlickWrap an image by looking at each image's styling. Just make sure you've got the padding css style on your image:

<html>
    <head>
        <title>jQSlickWrap Demo 2</title>
        <script src="./jquery-1.3.2.min.js" type="text/javascript"></script>
        <script src="./jquery.slickwrap.js" type="text/javascript"></script>
        <style type="text/css">
            .wrapReady {
                float: left;
                padding: 30px;
            }
        </style>
        <script type="text/javascript" charset="UTF-8">
            $(document).ready(function(){
                $('.wrapReady').slickWrap();
            });
        </script>
    </head>
    <body>
        <img src="./myImage.jpg" class="wrapReady" />
        <p>Lots of text goes here..</p>
    </body>
</html>

See it in action here!

Example 3 - Specifying Settings

In addition to being able interpret some settings from the CSS styling on image elements, it is also possible to specify several other settings to customize the way SlickWrapping will be done.

Settings:

  1. bgColor - The background color to use when examining the contents of the images resulting from a query. If no value is given, jQSlickWrap will try to determine the background color of the image from the image's top-left pixel.
  2. cutoff - The maximum allowable "distance" between a pixel's color and the background color that will qualify that pixel as being considered as part of the background. Defaults to 5.
  3. resolution - The height of the div elements to be created. Default value is 20.
  4. bloomPadding - Whether or not to use the advanced "bloom" algorithm to calculate precise padding distances. This is very slow in the current version, so the default value is false.
<html>
    <head>
        <title>jQSlickWrap Demo 3</title>
        <script src="./jquery-1.3.2.min.js" type="text/javascript"></script>
        <script src="./jquery.slickwrap.js" type="text/javascript"></script>
        <style type="text/css">
            .wrapReady {
                float: left;
                padding: 30px;
            }
        </style>
        <script type="text/javascript" charset="UTF-8">
            $(document).ready(function(){
                $('.wrapReady').slickWrap({
                    bgColor: {              // use red as the background color
                        r: 255,
                        g: 0,
                        b: 0,
                        a: 255
                    },
                    cutoff: 10,             // let there be a tolerance of 10
                    resolution: 15,         // create divs of height 15
                    bloomPadding: false     // let's not use bloom
                });
            });
        </script>
    </head>
    <body>
        <img src="./myImage.jpg" class="wrapReady" />
        <p>Lots of text goes here..</p>
    </body>
</html>

See it in action here!