Skip to content

Instantly share code, notes, and snippets.

@mezzoblue
Created August 16, 2010 17:09
Show Gist options
  • Save mezzoblue/527303 to your computer and use it in GitHub Desktop.
Save mezzoblue/527303 to your computer and use it in GitHub Desktop.
I'm working on a client-side image processing library, prospectively named PaintbrushJS.
I plan to develop in the open on GitHub, there are just a few loose ends to clean up
before I push the initial source. This is the biggie, since I don't want to change it
after I make a decision.
It would be helpful to read my description and subsequent comments on here to get the
gist of the problem:
http://dribbble.com/shots/45454-Canvas-Effects
My question is the best way to pass filter arguments to the script, assuming I want to
do that at the markup level. Currently I have an init script that defines things like
noise amount and colour tint RGB value, but ideally I'd like to do it in markup, as
attributes of the elements I'm manipulating. I think my options basically come down to
classes and data- attributes.
An example. The noise filter requires two additional parameters, a string to specify
mono/colour, and an integer between 0 and 100 to control amount. Both ways could work:
<img src="lighthouse.jpg" class="filter-noise noise-mono noise-amount-50">
<img src="lighthouse.jpg" class="filter-noise" data-noise-type="mono" data-noise-amount="50">
Though more verbose, it feels like the second is the "right" way, and will be easier
to parse. Am I correct in this thinking? Am I overlooking anything? Is there a third,
better way I'm not aware of?
@brianleroux
Copy link

+1 data attributes

might want to namespace them. data-pb-noise-type

@AndyCouch
Copy link

Your example is exactly why the "data-" attribute was created. I agree that the second method is the right way.

@mezzoblue
Copy link
Author

@brianleroux - yep, namespacing will be a must, just tried to keep it simple for this example.

@DavidOrchard
Copy link

2nd is much easier because doing a regex match on an attr value is harder than simple @attr selector.

@devongovett
Copy link

Yep, I also give a +1 to data attributes. Try to make the names as short as possible for convenience, but also be sure to namespace them. Point: don't be too verbose!

@dustinsenos
Copy link

The first question that comes to mind, is why use a classname at all?

< img src="lighthouse.jpg" data-pbjs-filter="noise" data-pbjs-type="mono" data-pbjs-amount="50">

Something like the above with some nice JS parsing could do the trick. I've also added "data-pbjs" to create a name space for all PaintbrushJS filters / settings to reside in. This will help avoid clashes in naming conventions down the road.

@duanestorey
Copy link

I personally like the first way. Hardcoding data attributes just seems wrong to me somehow, similar to hardcoding CSS attributes in markup. I personally think it might be more maintainable to define a class, such as mono-noise-filter-1 and apply that to all elements with the same requirements, that way you can simply change a few Javascript parameters later on and have them apply to all images in the markup.

@DavidOrchard
Copy link

you could also shift a bit of the complexity on to the parser by coming up with a structured attribute, like
<img src="lighthouse.jpg" class="filter-noise" data-noise="mono,50">.

YMMV on whether that's easier or harder to author.

@johnholdun
Copy link

Data attributes, especially if all the keys are known values. I've done something like the former and while it works, it isn't terribly pretty on either end.

@trovster
Copy link

The correct way, as you put it, is using the data attribute, so I'd go with that.

jQuery has the metadata plugin which would use a tweaked version of the class based idea. It would end up being the following:

<img src="lighthouse.jpg" class="filter-noise {noise: 'mono', noise-amount: '50'}">

@brianleroux
Copy link

could put a json config in an html comment right after the element if things are too complex. yeah: i'm a wildman / crazy like that

@mezzoblue
Copy link
Author

@trovster - specifically trying to avoid dependence on an external library. I'm making this one standalone. (though jQuery ports are probably likely, eventually)

@davemo
Copy link

davemo commented Aug 16, 2010

How about implementing something similar to the way jQuery's .data() function works? It just allows you to store key,value pairs as meta data on the DOM element in question. http://api.jquery.com/data/

I prefer this option to using data- attrs as a custom object that stores the meta data feels more like a proper "domain" separation of concerns ;)

*Edit: I'm not suggesting you use the jQuery solution, just that you see how the .data() func is written and implement your own version internally.

@devongovett
Copy link

I think that there should be a way to do this from JS as well. What if I want to change the effect after the initial page load?

@brianleroux
Copy link

I love how this degraded into a lets make it work like jquery after dave explicitly said he wanted it to be a declarative style api. (For which an imperative style api would be needed anyhow.)

@mezzoblue
Copy link
Author

@DavidOrchard @davemo - both of those suggestions look like they might be a really elegant way of doing it. Problem is parsing, not entirely sure if I've got the chops to make it happen. Maybe that's a post-release nice to have.

@devongovett - yep, I'm thinking of that too. There's a bigger problem where the initial filter is destructive, so the first step would be saving a copy in memory, then I could worry about changing after load. But animation / post-load changes are on my radar.

@duanestorey
Copy link

Another argument for the first method is that many image algorithms, for example sharpening, depend on the display resolution of the final device. A real world example of that would be changing the parameters for a sharpening algorithm when the iPhone 4's retina display is detected (which can you do via Javascript). So you would simply vary parameters in the JS initialization code for your library but keep the class in the markup the same.

@johnboxall
Copy link

Data attributes. We're using the same approach for mobile widgets. The namespacing makes it verbose, but it feels right.

Related articles:
http://ejohn.org/blog/html-5-data-attributes/
http://unspace.ca/discover/attributes/

@peol
Copy link

peol commented Aug 16, 2010

You could also use something like data-pb-noise='{"type": "mono", "amount": 50}' and run it through a JSON-parser, that'll enable you to still have all the data at markup level, while keeping it rather small (compared to other examples).

Running it through a JSON parser will also allow you to get typed values, which never is a bad thing. :-)

@sorccu
Copy link

sorccu commented Aug 16, 2010

There's a third way (but not necessarily better in any way): use URL parameters in the src attribute and parse them. The most obvious downside (or perhaps upside in some cases) is they get sent to the server. Just throwing it out there.

@unconed
Copy link

unconed commented Aug 16, 2010

-1 on the classes. With CSS3 selectors, any benefit you might expect to get from them no longer applies...

Copy link

ghost commented Aug 16, 2010

I first thought of data-* too, but this could get very repetitive... and it's presentation information.

Why not supply two ways to use this... data-* attributes AND a json file somewhere in the global scope. Something similar to behavior.js, like so:

var paintbrushfx = [
{ which: 'img.fx-bw', what: 'noise', args: { mono: true, ammount: 50 } },
{ which: '#list img', what: 'blackandwhite' },
{ which: '#list img:hover', what: 'normal' }
];

Extra points if you manage to support :hover and other basic interactions... but see? It would have to be a way to go back to normal (ie, original).

@silentrob
Copy link

Data Attributes are the right way to go, or pure JavaScript.

@jjenzz
Copy link

jjenzz commented Aug 16, 2010

+1 for data attributes or something similar to jQuerys $.data();

Copy link

ghost commented Aug 17, 2010

Dave, I've been going over this in my head...

I believe a simple parser could be written (I've made an attempt in firebug and worked) to achieve that JSON object from a css-like file:

img.fx {
noise: amount=50, mono;
black-and-white;
};

into:

[
{ which: 'img.fx', fx: [ { what: 'noise', args: { mono: true, amount: 50 } }, { what: 'black-and-white' } ]
]

This would make it super-simple for webdesigners to use this. Instead of making them know javascript, they would only have to pick up a syntax similar to css...

@mezzoblue
Copy link
Author

Best of both worlds I think. I'm writing it as data- attributes that create a JSON config object, and it's working swimmingly. Swapping out for a literal JSON file later will be cake.

Thanks all for the help!

Copy link

ghost commented Aug 17, 2010

Awesome, Dave. Writing a parser from the example I gave to your json object will also be possible. Even if not in the vanilla package, I can write it for myself.

Looking forward to seeing this in action! :-D

(ps: think of sprites... it might be helpful.)

@mezzoblue
Copy link
Author

Oh yeah, should probably mention here that the library is now public: http://github.com/mezzoblue/PaintbrushJS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment