-
-
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? |
Your example is exactly why the "data-" attribute was created. I agree that the second method is the right way.
@brianleroux - yep, namespacing will be a must, just tried to keep it simple for this example.
2nd is much easier because doing a regex match on an attr value is harder than simple @attr selector.
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!
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.
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.
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.
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.
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'}">
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
@trovster - specifically trying to avoid dependence on an external library. I'm making this one standalone. (though jQuery ports are probably likely, eventually)
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.
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?
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.)
@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.
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.
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/
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. :-)
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.
-1 on the classes. With CSS3 selectors, any benefit you might expect to get from them no longer applies...
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).
Data Attributes are the right way to go, or pure JavaScript.
+1 for data attributes or something similar to jQuerys $.data();
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...
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!
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.)
Oh yeah, should probably mention here that the library is now public: http://github.com/mezzoblue/PaintbrushJS
+1 data attributes
might want to namespace them. data-pb-noise-type