Subscribe: Acko.net
http://acko.net/tag/jquery/atom.xml
Added By: Feedage Forager Feedage Grade B rated
Language:
Tags:
bar  color  css  drupal  element foo  element  elements  farbtastic  foo bar  foo  form  function  javascript  jquery  page 
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics
Preview: Acko.net

Acko.net





Updated: 2016-05-12T20:06:53+02:00

 



Projective Texturing with Canvas

2008-11-11T00:00:00+01:00

Update: People keep asking me to use this code, apparently unaware this has been made obsolete by CSS 3D. So it's gone now.

The Canvas tag's popularity is slowly increasing around the web. I've seen big sites use it for image rotation, graph plotting, reflection effects and much more.

However, Canvas is still limited to 2D: its drawing operations can only do typical vector graphics with so-called affine transformations, i.e. scaling, rotating, skewing and translation. Though there have been some efforts to try and add a 3D context to Canvas, these efforts are still experimental and only available for a minority of browsers through plug-ins.

So when my colleague Ross asked me if we could build a Cover Flow-like widget with JavaScript, my initial reaction was no... but really, that's just a cop out. All you need are textured rectangles drawn in a convincing perspective: a much simpler scenario than full blown 3D.

(image)

Perspective views are described by so-called projective transforms, which Canvas2D does not support. However, it does support arbitrary clipping masks as well as affine transforms of both entire and partial images. These can be used to do a fake projective transform: you cut up your textured surface into a bunch of smaller patches (which are almost-affine) and render each with a normal affine transform. Of course you need to place the patches just right, so as to cover any possible gaps. As long as the divisions are small enough, this looks convincingly 3D.

So some hacking later, I have a working projective transform renderer in JavaScript. The algorithm uses adaptive subdivision to maintain quality and can be tuned for detail or performance. At its core it's really just a lot of linear algebra, though I did have to add a bunch of tweaks to make it look seamless due to annoying aliasing effects.

Unfortunately Safari seems to be the only browser that can render it at an acceptable speed, so this technique is just a curiosity for now. The current code was mostly written for readability rather than performance though, so it's possible it could be optimized to a more useful state. Feel free to browse the code.

A real 3D Canvas in the browser would obviously rock, but you can still do some nifty things if you know the right tricks...




Abusing jQuery.animate for fun and profit (and bacon)

2008-09-22T00:00:00+02:00

The days of static UIs that only have jarring transitions between pages are pretty much over. With frameworks like CoreAnimation or jQuery, it's easy to add useful animations to applications and webpages. In the case of jQuery, you can easily animate any CSS property, and you get free work-arounds for browser bugs to boot. You can run multiple animations (of arbitrary duration) at the same time, queue animations and even animate complex properties like colors or clipping rectangles. But what if you want to go beyond mere CSS? You might have a custom widget that is drawn using , whose contents are controlled by internal variables; maybe you're using 3D transformations to scale and position images on a page, and simple 2D tweening just doesn't cut it. In that case, it would seem you are out of luck: jQuery's .animate() method can only be applied to a collection of DOM elements, and relies heavily on the browser's own semantics for processing CSS values and their units. However thanks to JavaScript's flexibility and jQuery's architecture, we can work around this, and re-use jQuery's excellent animation core for our own nefarious purposes. Hackity hack hack First, we need an object to store all the variables we wish to animate. We use an anonymous
outside of the main document, so that jQuery's DOM calls still work on it. We simply add our own properties to it: var vars = $.extend($('
')[0], {   foo: 1,   bar: 2,   customAnimate: true,   updated: true }); In this case, our properties are foo and bar. We also set customAnimate and updated to identify this object (see below). Next we need to override jQuery's default step function, which gets called for every step of an animation, and applies new values to an element's CSS properties.    // jQuery.fx.step._default     _default: function(fx) {       fx.elem.style[fx.prop] = fx.now + fx.unit;     } We can replace it using the following snippet: var $_fx_step_default = $.fx.step._default; $.fx.step._default = function (fx) {   if (!fx.elem.customAnimate) return $_fx_step_default(fx);   fx.elem[fx.prop] = fx.now;   fx.elem.updated = true; }; With the new step function, jQuery will check for the presence of a customAnimate property on any element it is animating. If present, it will assign the (unit-less) value to element.property rather than element.style.property and mark the element by setting element.updated to true. Now we're ready to animate, using the normal $.animate syntax: $(vars).animate({ foo: 5, bar: 10 }, { duration: 1000 }); The values vars.foo and vars.bar will now smoothly change over time. You can use any of jQuery's animation abilities as usual. Now what about that updated variable? Well to actually use these animated values, you will need some kind of timer or step callback to read them back and draw them on the page. If you're using , you need to redraw your entire widget for every change, but you don't want to be wasting CPU time by constantly refreshing it. Furthermore, if you're running multiple animations at the same time, you'll want to aggregate all your property changes into a single redraw per frame. This is easy with the updated property and a simple timer: setInterval(function () {   if (!vars.updated) return;   vars.updated = false;      drawWidget(); }, 30); Now your widget will only refresh itself when its values are changed by the animation step function we defined earlier, and very few CPU cycles are wasted. As a plus, you can render updates as fast or as slow as you want, without affecting the duration[...]



jQuery OSCMS presentation slides

2007-03-23T00:00:00+01:00

Update: a raw video is now available of (almost) the entire session. Thanks to Jon F Hancock for recording it.

Today I did my second session at OSCMS, which was basically a repeat of the jQuery talk I did at DrupalCon Brussels.

You can download a PDF (2.2MB) of the (slightly tweaked) presentation slides.




ComicJuice gets even better

2007-03-09T00:00:00+01:00

I finished some more tweaks to ComicJuice:

  • IE6 and 7 are now supported, thanks to the amazing ExplorerCanvas by Google. It emulates the tag in IE, meaning that client-side scriptable vector graphics are now available on all the major browsers (IE, Firefox, Safari, Opera). I doubt Konqueror will be far behind.

    This opens up some cool abilities, like dynamic in-page graphs, mini-widgets (sliders, dials, maps, ...) and even pure JS games. There's a bunch of examples linked on Wikipedia (though most don't use ExplorerCanvas yet).

  • I added support for uploading your own images rather than using pictures on the web. It uses a customized and themed version of core's JS uploader.

    (image)

  • I improved the clipping of speech bubbles so there should be less useless whitespace around comics, especially when embedding them.



Expanding Textareas

2007-01-20T00:00:00+01:00

See the Drupal.org issue.

(object) (object) Quicktime embedding doesn't seem to be working. Try downloading the file.




On Breaking Things

2007-01-05T00:00:00+01:00

See the Drupal.org issue.

(object) (object) Quicktime embedding doesn't seem to be working. Try downloading the file.




jQuery Menu Scout

2006-12-07T00:00:00+01:00

Updated video: now also highlights deep links (though gray, not white), bubbles are prettier and aligned better and video capture is smoother. I also changed the music to please termie.

Out of a whacky conversation on IRC comes the latest treat for Drupal 5.0.

The new administration section is nice, but it's a big adjustment for 4.7 users. It's not immediately obvious where to go to find a certain option. Wouldn't it be handy if you could find any administration page with a couple of keystrokes? Something like Apple Spotlight?

Today's usability special: a nice slice of jQuery with some search module on the side, sprinkled with menu magic and topped off with some sexy CSS. Feast your eyes on this:

(image)
(MPEG-4 movie)

Patch is available on drupal.org.




fQuery

2006-11-23T00:00:00+01:00

fQuery fQuery is a Drupal module to help you deal with Form API arrays. Inspired by the jQuery library, it lets you find form elements using a simple and intuitive selector scheme, based on CSS. Download fQuery is maintained in the Drupal.org Contributions repository. Downloads are on the fQuery project page. To check out the included demo, install the module, copy example.php to the site root and visit it with your browser. Usage When fQuery is installed and enabled, use the f(); function to make queries. For example, selecting all collapsible fieldsets in a form is done using: Any module that uses fQuery should indicate its dependency in its .info file. Overview The following table summarizes how fQuery maps CSS concepts to Form API: CSSForm API Tag namesField types e.g. textfield Class namesBinary field attributese.g. .collapsible IDsField array keyse.g. 'status' HTML attributesField propertiese.g. #size HTML attributese.g. class. Here are some example queries: fieldsetAll fieldsets [#type=fieldset]All fieldsets (alternative) #statusAll elements with array key name 'status' .resizableAll items with '#resizable' set to true. [#resizable]All items with '#resizable' set to a non-empty value when cast to string. [#title=Authored by]All elements whose title is 'Authored by' [#description*=http://drupal.org/]All elements who link to drupal.org in their description. [class~=ponies]All elements whose #attributes => ('class' => '...') property contains the word ponies fieldset:not(.collapsible)All fieldsets which aren't collapsible (:not cannot be nested) fieldset > textfield:first-childAll textfields that are at the beginning of a fieldset textfield + textfieldAll textfields that come right after another textfield. textfield ~ textfieldAll textfields that are preceded by at least one other textfield (siblings only). Supported operators These operators can be combined into complex selectors, according to the CSS syntax. See the examples above. Note: All the [...] operators can be applied both with and without '#' in the attribute name to select Form API properties (like '#required' or '#size') instead of HTML attributes (like 'class' or 'title'). *Any element fooAn element of type foo [foo]An element with a "foo" HTML attribute [foo="bar"]An element whose "foo" HTML attribute value is exactly equal to "bar" [foo~="bar"]An element whose "foo" HTML attribute value is a list of space-separated values, one of which is exactly equal to "bar" [foo^="bar"]An element whose "foo" HTML attribute value begins exactly with the string "bar" [foo$="bar"]An element whose "foo" HTML attribute value ends exactly with the string "bar" [foo*="bar"]An element whose "foo" HTML attribute value contains the substring "bar" :nth-child(n)An element, the n-th child of its parent :nth-last-child(n)An element, the n-th child of its parent, counting from the last one :first-childAn element, first child of its parent :last-childAn element, last child of its parent :only-childAn element, only child of its parent :emptyAn element that has no children .fooAn element whose binary property "#foo" is true #fooAn element with array key equal to "foo" :not(s)An element that does not match simple selector s (the operators below are not allowed) E FAn F element descendant of an E element E > FAn F element child of an E element E ~ FAn F element preceded by an E element E + FAn F element immediately preceded by an E element [...]



Mouse Handling and Absolute Positions in JavaScript

2006-10-27T00:00:00+02:00

As I was working on the new recolorable Garland Drupal theme, I noticed that suddenly my Farbtastic color picker wasn't working right anymore in IE. A lot of headscratching later, I found the cause and discovered a useful trick for dealing with mouse coordinates in JavaScript. Essentially, when you click on Farbtastic, the mouse position is compared to the position of the color picker, so we can determine which color you clicked. Sounds simple? Well, no. There is no direct DOM API to get an elements's absolute position on the page. The most common technique to find it is to iterate through an element's offsetParents until you reach the root, and add together all the offsets:   function getAbsolutePosition(element) {     var r = { x: element.offsetLeft, y: element.offsetTop };     if (element.offsetParent) {       var tmp = getAbsolutePosition(element.offsetParent);       r.x += tmp.x;       r.y += tmp.y;     }     return r;   }; Unfortunately, even this does not work well. Various browsers have various quirks, but (no surprise) IE wins the contest hands down. When you try to resolve absolute positions in any sort of advanced CSS-based layout, the return coordinates are often completely wrong. This is exactly what was happening in the new (completely tableless) Garland theme. After trying various ways to correct the absolute values, I decided I didn't want to waste hours of my life cleaning up after somebody elses mess. And of course, hardcoding in the correction is mostly useless in a dynamic CMS like Drupal. I did come up with an alternative which works well enough, and is perfectly suited for making self-contained HTML widgets: that's the most common use case after all. You see, aside from the absolute mouse position (event.pageX/Y) we often also get the mouse position relative to the clicked element (event.offsetX/Y). Now, if we try to resolve these coordinates back to the root of the page, we end up with the same problem. The trick is to realize that we often don't need completely absolute coordinates: all we need is coordinates relative to a common reference frame. So, we need to find the closest, common offsetParent for the clicked element and the reference element, and then compare the coordinates in that frame. The snippet below achieves this. As most of the bad offsetParent numbers are located very high up in the page hierarchy, they are practically never used with this approach. Typically you only go up one or two offsetParents and there is no error. Some browsers don't provide the offsetX/Y information (e.g. Firefox) or tend to screw it up (e.g. Opera), but luckily they are the ones that provide (mostly) accurate pageX/Y coordinates, even in exotic layouts. So using that as a fallback, we end up with the following function, which works in every browser I've tried:   /**    * Retrieve the coordinates of the given event relative to the center    * of the widget.    *    * @param event    *   A mouse-related DOM event.    * @param reference    *   A DOM element whose position we want to transform the mouse coordinates to.    * @return    *    A hash containing keys 'x' and 'y'.    */ &nb[...]



fQuery Sneak Preview

2006-09-29T00:00:00+02:00

Update: fQuery has been released.

Here's a sneak preview of something I've been working on since DrupalCon Brussels...

I've noticed that most hook_form_alter() uses need to look for certain elements in the $form array. For example, you want to make all resizable textareas fixed height. This means you have to iterate over $form and do recursion, find the matching elements and change them. That sucks.

What if you could just find all elements with certain properties with one line of code, and do stuff with them? Doesn't this sound at all familiar?

Enter fQuery. In a hook_form_alter(), you could do:

$query = f('textarea.resizable', $form);
foreach ($query as &$element) {
  $element['#resizable'] = FALSE;
}
?>

Neat huh?




jQuery DrupalCon Talk

2006-09-23T00:00:00+02:00

Greetings from DrupalCon. I just finished my jQuery talk (and got a lot of positive response). If you're interested in the slides, you can download them in PDF format.

A video of the presentation will be made available in time, once the tapes reach the editor and get put online. Thanks to the volunteers responsible for this!

(photo by Dries Knapen)




jQuery is in Drupal core!

2006-09-01T00:00:00+02:00

After a long wait, the awesome jQuery library has finally been committed to Drupal core. jQuery 1.0 will be part of the next major Drupal release, for which the code freeze is about to begin.

While we did take advantage of jQuery to add some minor glitter to our JavaScript features, the main advantage is that it makes it easier to develop JavaScript features. Using a simple CSS-based syntax, you can manipulate any element in the page easily. Loading in chunks of HTML through Ajax is a snap too.

Hopefully jQuery will help more Drupal developers look at using JavaScript to build kick-ass interfaces in the browser.

Thanks to John Resig and the jQuery community for making such an awesome library. On the Drupal site, thanks to: Konstantin, Steve, Angie, Ted, Jeff and everyone else who tested the patch.

See also: 'New Wave' JavaScript in Drupal: jQuery.

PS: There will still be some bugs in there that I haven't found, but that's what the code freeze is for ;).




Farbtastic Color Picker

2006-07-14T00:00:00+02:00

jQuery Plug-in Farbtastic is a jQuery plug-in that can add one or more color picker widgets into a page through JavaScript. Each widget is then linked to an existing element (e.g. a text field) and will update the element's value when a color is selected. Download Farbtastic 1.2 - January 8, 2007 (License: GPL). Demo Farbtastic uses layered transparent PNGs to render a saturation/luminance gradient inside of a hue circle. No Flash, no pixel sized divs. Click and drag over the selector to try it out. Color: Basic Usage Include farbtastic and farbtastic.css in your HTML: See demo1.html and demo2.html for an example (jquery is not included!). Styling The color picker is a block-level element and is 195x195 pixels large. You can control the position by styling your placeholder (e.g. floating it). Note that the black/white gradients inside wheel.png and mask.png were generated programmatically and cannot be recreated easily in an image editing program. Advanced Usage jQuery Method $(...).farbtastic() $(...).farbtastic(callback) This creates color pickers in the selected objects. callback is optional and can be a: DOM Node, jQuery object or jQuery selector: the color picker will be linked to the selected element(s) by syncing the value (for form elements) and color (all elements). Function: this function will be called whenever the user chooses a different color. It should have the following signature: function callback(color) { ... } With color the chosen color in hex representation (e.g. '#123456'). Object $.farbtastic(placeholder) $.farbtastic(placeholder, callback) Invoking $.farbtastic(placeholder) is the same as using $(placeholder).farbtastic() except that the Farbtastic object is returned instead of the jQuery object. This allows you to use the Farbtastic methods and properties below. Note that there is only one Farbtastic object per placeholder. If you call $.farbtastic(placeholder) twice with the same placeholder, you will get the same object back each time. The optional callback argument behaves exactly as for the jQuery method. Methods .linkTo(callback) Allows you to set a new callback. Any existing callbacks are removed. See above for the meaning of callback. .setColor(string) Sets the picker color to the given color in hex representation (e.g. '#123456'). .setColor([h, s, l]) Sets the picker color to the given color in normalized HSL (0..1 scale). Properties .linked The elements (jQuery object) or callback function this picker is linked to. .color Current color in hex representation (e.g. '#123456'). .hsl Current color in normalized HSL (e.g. [0.3, 0.4, 0.5]). [...]



A Taste of Things to Come

2006-06-29T00:00:00+02:00

(object) (object) Quicktime embedding doesn't seem to be working. Try downloading the file.




'New Wave' JavaScript in Drupal: jQuery

2006-06-23T00:00:00+02:00

After an Ajax related chat today, a battle plan has been created for integrating the jQuery Javascript library into Drupal. As this is the result of a long discussion in private mails and on Drupal Groups, I wanted to jot down the reasons in one place for future reference.

Though several people have suggested integrating third party JavaScript libraries in Drupal, I rarely heard good arguments for doing so. The last thing we want is just to add some 'bells and whistles'. I wanted a good, small platform that would serve as a suitable base for both the (relatively small) core JavaScript work as well as the extended needs of the Drupal community at large.

The most important thing is to keep in mind the context of the Drupal system. We have a very advanced code base on the server-side already: text filtering, access control, localization, form API, theming, etc. A well-written, Drupal-like module has to use these systems to integrate with Drupal. Heavy client-side JavaScript applications are not likely to happen soon, as that will lead to self-contained functionality that does not 'play nice' with others.

This means that browser platforms such as Dojo are not good candidates. Though well written, they are simply overkill for what we need. When we look for small, functional libraries, jQuery stands out as the most suitable:

  • It focuses on making common JS tasks easy to do, without much fuss or overkill. There are no grand claims, just a set of well written, self-contained utilities. This means you can focus on your functionality.
  • It is centered around CSS-like queries. Finding and interacting with DOM elements is done with a CSS selector. This means it is easy to pick-up even for those with no JavaScript knowledge.
  • It provides much bang for your buck. In only 10KB, you get the CSS-query system, basic Ajax, basic animations and smart events.
  • It is built by smart, dedicated people. In fact, John Resig (the author) has personally gotten involved in discussions and answered our many questions.
  • It has a modular plug-in system. This means that contributed module authors can easily include advanced functionality, while we can keep core simple. Including an existing or custom plug-in is as simple as adding in another file.

To summarize: we chose jQuery because it is compact enough for core, easy enough for non-JS experts and because it provides a broad platform onto which rich contributed modules can be built.

The concrete steps for getting this stuff into Drupal:

  1. Remove those parts of drupal that have equivalents in jQuery, and rewrite the left-overs to use jQuery's APIs.
  2. Rewrite the other files in core to use jQuery functionality. This is mostly the replacing of complicated code with very simple calls.
  3. Add in new functionality that jQuery makes easy, thus proving how this was a smart move.

I'm confident we can get this done for Drupal 4.8.