Search Logger
Posts from:

Author Archive

In the YUI 3 Gallery: Matt Parker’s Resize Plugin

9:45 am - March 25, 2010 in Yahoo! User Interface Blog

About the author: Matt Parker (@Lamplightdb on Twitter) is the founder and developer at Lamplight Database Systems, a small company providing a fully-featured web-based management system for non-profits in the UK. Matt lives and works in North-West London. In this article, Matt discusses his new YUI 3 Gallery Resize plugin.

We use an awful lot of the different YUI 2 widgets and components in our main application, and love them! But I’d thought it was about time to start getting to grips with YUI 3, and decided I’d have a go at bringing YUI 2’s Resize Utility over to YUI 3. I also have longer term plans to write a diary widget, and if it was going to be in YUI 3 it would need some resizableness.

The result: My YUI 3 Gallery Resize plugin. The source is available on GitHub, and here is a functional example.

I decided to do it as a plugin, rather than a widget. As far as I can tell, plugins are like a pretty handbag or a pair of ostrich-skin shoes; they pretty up an existing element, but they’re not the be-all-and-end-all. Making an element resizeable felt like a plugin to me.

To use Resize, include the code in your page:

<script src="http://yui.yahooapis.com/combo?3.0.0/build/yui/yui-min.js&gallery-2010.03.23-17-54/build/gallery-resize/gallery-resize-min.js"></script>

Once you’ve got the module on the page, making an element resizeable is as easy as plugging it in:

YUI().use( "gallery-resize", function(Y){
  Y.one( "#elementId" ).plug( Y.Plugin.Resize );
} );

It seemed quite important to me that the config and API of YUI 3 versions of components that exist in YUI 2 should be similar, at least, or as much as they can be within the YUI 3 approach. So you can use the same config objects with this plugin as with the YUI 2 version, and I’ve provided the same API methods. I wrote the plugin code from scratch, but the CSS is copied directly from YUI 2, only changing the prefix from yui- to yui3-. This should help minimize the learning curve for people making the YUI 2 to YUI 3 transition.

Here’s an example with some more options, passed as an object as the second argument to plug():

YUI().use( "gallery-resize", function(Y){

  Y.one( "#elementId" )
   .plug( Y.Plugin.Resize,
         { draggable: true,
            ratio: false,
            height: 150,
            proxy: true,
            ghost: true,
            animate: true,
            autoRatio: true,
            handles: [ "t", "b" , "l", "r", "tl" , "tr" , "bl" , "br" ],
            hiddenHandles: false,
            hover: true,
            knobHandles : true,
            useShim: true,
            status: true,
            // this is new: a selector to find child elements within #elementId
            // that should be resized in proportion to the wrapper.
            wrappedEls: "img",
            // so is this: should the wrapper 'hug' the wrapped element?
            // this'll only work with one wrapped element.
            hugWrappedEl: true
             } );
 } );

There is one exception to the consistency with YUI 2: wrapping elements. My Resize Gallery module adds some div elements inside the element that’s being resized to give you drag handles. This is fine as long as the element accepts child nodes; but images, textareas and the like don’t. In YUI 2, the Resize Utility automatically (or if you tell it to) adds a wrapper element to your image (or whatever) to make it resizeable.

This is fine, but it isn’t so good with a plugin approach. Plugins plug in to a particular node, and are accessible as a property of that node. But if my plugin starts creating new parent nodes and attaches itself and its behaviour to that parent, the interface is a bit broken, and it gets confusing to use. So the bottom line is that you have to wrap your pictures yourself for now. This could be cast as an advantage; the wrapper element can contain a pile of images, say, and they could all be resized with the wrapper, but captions for them could be left alone.

I’d love feedback from users (in the brand new Gallery Resize forum) as to whether the plugin approach works for you — that is, do you like the convenience or would you prefer the additional convenience of a utility that automatically handled the wrapping of images and textareas? I have some other to-dos still, as well; for example, I’ve not yet got wired the Events, there’s some re-arranging odds and ends (pulling out the CSS class names), and some performance and size optimisations yet to do. I haven’t completed cross-browser testing, either; if you’re using Resize with a Mac, particularly, I’d love feedback on how it’s working for you.

 

Improving perceived site performance with spinners

12:33 pm - November 11, 2010 in Yahoo! User Interface Blog

At the London Ajax meetup this week, Piotr (one of the creators of the rather good jsfiddle.net talked about spinners — the pretty common “I’m doing something” indicator — and how users perceive them.

Apparently, people perceive Chrome to be faster in part because the little activity indicator keeps changing — it appears and disappears, and changes speed — while a page is loading. This sense of something happening persuades people that something is in fact happening, and faster, even if the actual speeds are identical.

So Piotr set up a randomized survey, comparing perceptions of load speed after clicking two buttons — it’s here if you’re interested. When you click the button there’s a delay before the spinner is shown, and then a short (random) time later the results are shown. Then you click another button, and the same thing happens. And then you say which was faster. He also allowed for a “this thing seems broken option”. (If you’re going to do the survey, do it now and then come and read the conclusions — I don’t want to spoil it for you!).

The results are here. The conclusion is that by delaying the display of the spinner slightly, users perceive things to be happening quicker. But wait too long and they start to think something’s broken — 0.4s seemed to be the optimal delay, from the survey results. And it may be worth thinking about other indicators if things take longer — add a “loading…” text overlay after 1 sec, perhaps.

 

Table footer statistics for YUI 2 DataTable

7:00 pm - January 13, 2011 in Yahoo! User Interface Blog

The YUI 2 DataTable does a lot. But one of the things it doesn’t do is anything with a table footer, where you might expect to find totals, averages or other summary data. So I’ve extended DataTable to add summary data for numeric data.

Getting it going

First, to use it: you’ll need some code from github – there are three js files, and you’ll need all of them on your page after the YUI DataTable js file. And you might want to change the namespace – we use YAHOO.LPLT.DataTable as the extension of YAHOO.widget.DataTable. I’ll explain a bit more about these files below.

You set up your datatable as normal, but there are three things you need to do to get the summary working:

  1. Make sure your datasource specifies “number” parsers for any fields you want to summarise, particularly if you’re doing inline cell editing:
    myDataSource.responseSchema = {fields: [
       {key: "quantity", parser: "number"}
       /* etc... */
    ]};
    
  2. Add a config key-value of columnStats: true in your column definition array:
    var myColumnDefs = [
        {key: "quantity", label: "Quantity", columnStats: true}
        /* etc... */
    ];
    

    for the columns that you’d like summarised. (The total of your ‘id’ column is probably not very helpful!).

  3. Tell the datatable which statistics to calculate:
    var myDataTable = new YAHOO.LPLT.DataTable("exampleEl",
        myColumnDefs,
        myDataSource,
        {columnStats: {on: true, stats: ['sum']}}
    );
    

    This is the simplest possible way to configure the column statistics, but you can add extra statistics, customise the labels, and more.

There’s an example on github to play with.

A few points:

  • The footer will change with your table. So if you show/hide columns, move them around, add new ones, add/remove rows, sort, or use inline cell editors, the footer will update the UI and statistics accordingly.
  • You can add as many rows to the footer as you like, one row for each statistic. As it stands, you can have mean, median, sum, min, max, range, stdev, variance, or varianceUnbiased. The ‘stats’ item in the configuration is an array: just add the statistics you’d like to this array (e.g. stats: ["min", "median", "stdev"]).
  • The table footer will use any formatters specified for that column.
  • If you have a paginator, you can choose whether the statistics shown are for the entire table or just the currently visible page. Add pagedTotals: true to the columnStats object to have page statistics.
  • The ‘stats’ array in the config object can also include object literals, with keys ‘label’ and ‘fn’. fn is the function that will calculate statistics – either a string like ‘min’ or a function that returns a number. The example on github shows how you could do a ‘weighted total’ using data from two columns.

More on the actual extension code

The main file, YAHOO_DataTable_colStats.js, adds a couple of protected properties to the datatable, a few protected methods, and two public methods, colStatsRefresh which will re-calculate and redraw the table footer, and colStatsGetRecordSet, which returns an array either of all records, or just those visible, depending on the value of pagedTotals. The first may be useful if you’re making changes to the table that don’t fire useful events (for example directly changing data in the underlying RecordSet); the second if you’re using custom summary functions.

YAHOO_DataSource_patch.js adds a parseField(key, value) method to DataSource. This is needed when you have textbox inline cell editors for numeric data; the editor returns a string, which is not parsed automatically, and so can’t be added. The parseField provides access to the parsers specified in the DataSource, to convert edited data.

YAHOO_util_Stats.js provides a standalone YAHOO.util.Stats class which wraps a (sorted) array of numeric data and provides the summary statistics. It’s only dependency is YAHOO.lang. A YAHOO.util.Stats instance is maintained by the DataTable for each column that is to be summarised, and caches some of the harder maths to improve performance. The strings passed in to the stats array (‘min’, ‘median’ etc) are methods of the YAHOO.util.Stats class, so you could easily add additional ones by adding to the prototype. Note though that they only have access to ‘their’ column’s data.

And finally

I’m pretty sure this isn’t going to work with scrolling datatables, so I’ve not even tried it! But if you find any problems or have ideas, do please put them on the github issue tracker.

About the author: Matt Parker (@Lamplightdb on Twitter) is the founder and developer at Lamplight Database Systems, a small company providing a fully-featured web-based management system for non-profits in the UK. Matt lives and works in North-West London.

 
 
 
 
 
 
It's All About Search | © clsc.net |
2012.05.1822:35
Tech used here: Valid HTML - Valid CSS - Valid RSS - JavaScript - PHP - Smarty - MySQL - and a partridge in a pear tree.