jwarby / jquery-awesome-cursor

jQuery plugin for using FontAwesome icons as custom CSS cursors
https://jwarby.github.io/jquery-awesome-cursor/
MIT License
179 stars 69 forks source link

Just an idea on how to implement it differently #13

Closed cauerego closed 9 years ago

cauerego commented 9 years ago

Wouldn't it make more sense to use it upon fa tag?

Something like this:

<i id="useme" class="fa fa-rss"></i>
<script>
  $('#useme').awesomeCursor({'hotspot', 'center'});
</script>

It would check if it's an i.fa and only execute then. Else, throw an error.

What you think?

jwarby commented 9 years ago

Not really - as of v0.1.0 you can use an alternative icon font, so the class name will not necessarily be 'fa'. The CSS class is declared as an option though, so it could probably be accounted for...

However, this approach does not allow specifying which element to set the cursor on. With the current implementation, you would do something like:

$('.editor').awesomeCursor('pencil');

to set the cursor on the .editor element. With the proposed changes, we would have to add the target element as an option, which doesn't feel right...

cauerego commented 9 years ago

It would make much more sense to setting up the icon. And yeah, I did miss that, but you could allow specifying which element with a parameter, which is also much more jQuery-ish:

.awesomeCursor('.editor');

As for using an alternative icon font, well, I don't see how that couldn't be implemented in this way. I just wanted to keep the suggestion simplified there.

jwarby commented 9 years ago

I don't know, I would argue that having the awesomeCursor function mutate the selected elements is more jQuery-ish, .e.g $('body').css('background', 'red')...

I'll leave this issue open for a while longer (another week or two) to see if anyone has anything to add this discussion, otherwise we'll stick with the current API.

cauerego commented 9 years ago

There is .append() and there is .appendTo(). Mutating the selected element is just one jQuery'ish approach and, while you're probably right - it must be the most common one - by having it the way it is now it makes so much harder to configure the FA (or whatever other image you want set as cursor).

Keep in mind javascript should be dealing with behaviour only, so configuring the layout and image configuration should all be either in the HTML or CSS. And FA already have its own way to setup which is not fully implemented with using the current function parameters. I also think it makes no sense to reinvent that wheel, since FA already configures the image, that's its whole purpose!

You could kinda merge both ideas here and just add an attribute selector (or whatever name):

$('body').awesomeCursor('#useme')

or

$('.editor').awesomeCursor({'selector': '#useme'});

I think I like this even better than the first idea. :)

jwarby commented 9 years ago

Which bits of FA aren't covered by the current implementation? From looking at the docs, the only thing it seems to be missing is stacked icons, which I didn't feel would be worth the effort to implement. The current implementation doesn't allow you to set custom CSS though, if that's what you were referring to....

I do quite like this second idea, but I would want to implement it alongside the existing API somehow. The use case that I built the plugin for was a drawing application; I wanted to define the default styles of the cursor easily by overriding $.fn.awesomeCursor.defaults, so I could then do something along the lines of: $('canvas#editor').awesomeCursor('pencil'). I also didn't want to force the user into having extra icons in the DOM that they may not need or want.

Ideally, it would be great to support this automagically, whereby the awesomeCursor function figures out that it's been given a selector and not an icon name. Unfortunately, there's no nice way to know if something is a valid selector - the most robust solution I have seen involves trying to use the string regardless, then catching the error that jQuery throws if it's invalid (see this Stack Overflow answer). We could try assuming that it is an icon name if it matches any elements or doesn't throw an error, but it sounds a bit hacky and could be unpredictable... and of course, we all know what assume makes of 'u' and 'me'

cauerego commented 9 years ago

I haven't reviewed everything that's missing, but yeah, I'd have said "at least" stacked icon, which by itself is quite a lot. Good cursor icons have black and white borders to work on top of any background color variation. Without stacking I believe no FA icon have that.

I'd say you shouldn't bother that much about keeping legacy and doing it this way would probably make the library much smaller, which is another huge plus (at least in theory and for practical edge cases such as low resources in an old or cheap smartphone).

I'm not sure why you're worried about "having extra icons in the DOM" but, in any case, there is the option to traverse the CSS only, without needing to go to the DOM. Both FA and javascript support doing this. And it still makes more sense having the designing part there rather than in the javascript.

Finally, if you do insist in keeping it this way, I don't see such a big problem with making it "magical" as you suggested. You could also make it even hackier and use some identifier for one or the other behaviour such as .awesomeCursor('ac-pencil') which will be make it very unlikely to exist beforehand. That's a hack already being used by FA anyway.

jwarby commented 9 years ago

It looks like other than stacked icons, spinning icons and a few irrelevant options (such as fa-border), everything is supported. In fact, the plugin actually allows greater configuration than FA's set of classes - for example, the plugin allows rotation by an arbitrary number of degrees (FA only provides classes for rotating by 90°, 180° or 270° and also outlines for cursors to be specified (see the plugin's options documentation).

I don't consider the current API to be legacy - I feel it offers a convenient, readable and easy-to-modify approach to setting a custom cursor. Also, which smartphones do you know of that would even have a cursor?

I'm not worried about the extra DOM nodes so much; I think that, in your use case, you are already using the icons you want to use as a cursor elsewhere in your application. This may not be the case for everyone, so I didn't want to force users into adding extra markup where they don't necessarily need or want it.

There's also no provisions for defining the cursor's hotspot with the proposed approach.

However, with all of that said, I think I have come up with a nice way of supporting both use cases: instead of specifying a string selector, you could pass a jQuery object or DOM element through:

$('#myCanvas').awesomeCursor($('i.pencil'), {
  hotspot: 'bottom left',
  // could provide optional overrides here too if desired
});

What do you think?

cauerego commented 9 years ago

Haha, true. No smartphones have a cursor! I was thinking just about possible processing power bottlenecks. And using FA icons elsewhere is certainly an edge case, but I'd argue having something that will show on the screen as a DOM element is not "extra markup". This is certainly also hard to define because mouse cursor is such a borderline topic.

The current API for configuring FA is not legacy, I just wished it would be. I wasn't aware the plugin does allow for greater configuration than FA, but I'd still keep only those extra configurations, such as hotspot, which makes all the sense. Maybe even more so if you moved it into the CSS settings so we could do something like:

.awesomeCursor($('i.pencil')).css({'ac-hotspot': 'bottom left'})

:-)

And yeah, I loved the suggestion! Much better than using any hacks.

jwarby commented 9 years ago

Ok cool, I will try and take a look this weekend, thanks! :)

cauerego commented 9 years ago

Awesome!! :D

jwarby commented 9 years ago

Ok, first things first - sorry it's taken me so long to get back to you.

I started implementing the feature, and then realised all I had done was make it extract the unicode character from the provided DOM element. I'm guessing that's not what you were after! I then realised that the desired behaviour is probably that the cursor looks exactly like the provided source element. To do that, we'd effectively need to turn a DOM element into a data URL (PNG image data). It is probably possible to do this using some crazy hacks, but you can understand why I don't want to go down that route :)

So, are my assumptions correct? If they are, can you think of a way to achieve what you want?

cauerego commented 9 years ago

Looks like the assumptions are correct, but I'm sorry I don't think I'd be able to help beyond this point.

I have no clue how you're making it currently work, but I assumed whatever it was doing to build the current PNG was being done by grabbing the image data from FA somehow.

If it would require such a different method to render the cursor, then this whole idea is probably not worth it. This was an idea for a different syntax building in which I could foresee more liberty, without considering anything else! ;P

jwarby commented 9 years ago

At the moment, it renders the icon character to an offscreen canvas and grabs the image data URL from that canvas.

It would certainly require a different approach, and I'm not sure that a reliable, cross-browser solution even exists...

So in light of all this, are you happy for me to mark this issue as can't/won't fix and close it?

cauerego commented 9 years ago

Thanks for asking me before closing this, but it's really up to you! :D

I don't quite understand how making an offscreen canvas wouldn't work for this, though. Isn't that "grabbing the image data from FA somehow"? If so, why would you require a different approach then?

jwarby commented 9 years ago

Haha, you're welcome - I just didn't want you to log on and get miffed if I'd closed it first!

Sorry that last comment was a little misleading. Here's how it works:

  1. Creates an <i> element offscreen with the correct FA class
  2. Extracts the unicode value for the icon from the rendered <i> element
  3. Creates a canvas, and sets font rendering color, stroke styles, etc, etc according to plugin options/defaults
  4. Renders the icon to the canvas by writing the unicode value in the correct font family
  5. Calls toDataURL on the canvas to get the data URL for the CSS cursor value

To achieve what we're discussing here, we would have to somehow get the correct unicode value from the source, and also extract the CSS in order to set the canvas properties accordingly.

Does that make it any clearer.... ?

jwarby commented 9 years ago

Closing due to inactivity

cauerego commented 9 years ago

Fair. :+1: