View Full Version : Image Map Highlighter Extension?
Eric24
20 Mar 2009, 9:52 AM
(Reposting here, at Saki's suggestion)
Is anyone aware of an Ext extension that's something like this for jQuery (http://drupal.org/project/jq_maphilight)?
What I'm trying to do is display a conventional HTML image w/imagemap in a panel, where each area highlights on mouseover and a click invokes some JS function. All of this is fairly easy, the only complex part maybe being the mouseover highlight, but before I started writing from scratch, I thought I'd ask.
If there is no such extension, any tips/ideas/suggestions (especially on how to handle the mouseover highlight) would be greatly appreciated.
Tnx!
Nigel
15 Jun 2011, 7:13 AM
Hi Eric
I know this was a couple of years back, but did you ever make any progress with your image map in ExtJS? I'm starting to look at this - I've seen the image map editor linked from http://www.sencha.com/forum/showthread.php?66552-imagemap
but as far as I can see, this just generates the raw HTML for the image and associated map, which is a help, but doesn't deal with the highlighting that you were asking for, or actually the original question in that thread which was about capturing the events from the image map in ExtJS.
I want to use Image Maps in my app as well - my expectation is that I'll make an image map control and capture the mouse clicks from the map - hopefully, there's enough information in the event to tell me which zone was clicked - if not, then I'd have to write code in the control to work that out from scratch, which would also mean having an array of all the zone co-ordinates as part of the control.
I thought I'd check in with you before I start head-scratching and experimenting...
Regards
Nigel
Eric24
15 Jun 2011, 7:21 AM
Hi Nigel,
No, it's still something I'm interested in (it's "on the very long list"), but other than some initial research into what options are out there, I didn't start any development.
Regards,
Eric
Nigel
15 Jun 2011, 9:30 AM
Eric
I've been having a bit of a play, and I've come up with the beginnings of a workable solution.
Ext.ux.ImageMap = Ext.extend(Ext.Component, {
hotZone: '',
autoEl: {
tag: 'img',
src: Ext.BLANK_IMAGE_URL,
border: 1
},
onRender: function () {
var el;
this.autoEl = Ext.apply({}, this.initialConfig, this.autoEl);
Ext.ux.ImageMap.superclass.onRender.apply(this, arguments);
el = this.getEl();
el.on('click', this.onClick, this);
el.on('mousemove', this.onMouseMove, this);
},
onMouseMove: function (e) {
var x, y, xy, elxy;
var currentHotZone;
elxy = this.el.getXY();
xy = e.getXY();
x = xy[0] - elxy[0];
y = xy[1] - elxy[1];
currentHotZone = '';
if (typeof this.hotspots !== 'undefined') {
Ext.each(this.hotspots, function(hs) {
if (x >= hs.left && x <= hs.right && y >= hs.top && y <= hs.bottom) {
currentHotZone = hs.name;
}
}, this);
}
if (currentHotZone !== '') {
if (currentHotZone !== this.hotZone) {
console.log('Entered zone ' + currentHotZone);
this.el.setStyle('cursor', 'pointer');
}
} else {
if (this.hotZone !== '') {
this.el.setStyle('cursor', 'default');
console.log('Leaving zone ' + this.hotZone);
}
}
this.hotZone = currentHotZone;
},
onClick: function (e) {
console.log('clicked ' + this.hotZone);
}
});
Ext.reg('ximagemap', Ext.ux.ImageMap);
EXAMPLE:
{
xtype: 'ximagemap',
src: 'http://mydomain.com/myimage.jpg',
hotspots: [{
name: 'hotspot1',
top: 65,
left: 23,
bottom: 120,
right: 80
}, {
name: 'hotspot2',
top: 140,
left: 36,
bottom: 180,
right: 95
}]
}
It doesn't actually use a classic HTML image map, as there's no real need - but it does only work for rectangular hotspot regions at the moment (I can't see that I'd need more than that).
To make this fully 'production ready', the console logging should obviously be replaced with suitable event generation, but hopefully this is enough to get the creative juices going. If you've got any ideas or suggestions for improvements, please share. If I make improvements, I'll update this thread.
Regards
Nigel
Nigel
16 Jun 2011, 7:36 AM
After some considerable head-scratching, I've now got QuickTips working as well - this involved creating an override to Ext.QuickTip to force the tip to display for the current target, as I'm registering and unregistering the tip as and when the cursor passes into one of the hotspots. These are not separate elements/components that can be registered individually with QuickTips in the normal way.
Simply add a 'qtip' config to each hotspot as shown in the example in the previous post.
Ext.ux.ImageMap = Ext.extend(Ext.Component, {
hotZone: '',
qtip: '',
autoEl: {
tag: 'img',
src: Ext.BLANK_IMAGE_URL,
border: 1
},
onRender: function () {
var el;
this.autoEl = Ext.apply({}, this.initialConfig, this.autoEl);
Ext.ux.ImageMap.superclass.onRender.apply(this, arguments);
el = this.getEl();
el.on('click', this.onClick, this);
el.on('mousemove', this.onMouseMove, this);
},
onMouseMove: function (e) {
var x, y, xy, elxy, EQ;
var currentHotZone;
elxy = this.el.getXY();
xy = e.getXY();
x = xy[0] - elxy[0];
y = xy[1] - elxy[1];
currentHotZone = '';
if (typeof this.hotspots !== 'undefined') {
Ext.each(this.hotspots, function(hs) {
if (x >= hs.left && x <= hs.right && y >= hs.top && y <= hs.bottom) {
currentHotZone = hs.name;
this.qtip = hs.qtip;
}
}, this);
}
if (currentHotZone !== '') {
if (currentHotZone !== this.hotZone) {
ConsoleLog('Entered zone ' + currentHotZone);
this.el.setStyle('cursor', 'pointer');
if (this.qtip !== '') {
EQ = Ext.QuickTips;
EQ.register({
target: this.el,
text: this.qtip
});
EQ.getQuickTip().showForTarget(this.el);
}
}
} else {
if (this.hotZone !== '') {
this.el.setStyle('cursor', 'default');
ConsoleLog('Leaving zone ' + this.hotZone);
if (this.qtip !== '') {
EQ = Ext.QuickTips;
EQ.getQuickTip().hide();
EQ.unregister(this.el);
this.qtip = '';
}
}
}
this.hotZone = currentHotZone;
},
onClick: function (e) {
ConsoleLog('clicked ' + this.hotZone);
}
});
Ext.reg('ximagemap', Ext.ux.ImageMap);
// This override needed to force QuickTip to display the tip for current target.
// Since ImageMap has to register/unregister the tips on entry to each zone, rather than on initial
// instantiation. Because of this, the normal mechanism of QuickTip's onTargetOver method receiving
// an event doesn't work.
Ext.override(Ext.QuickTip, {
showForTarget: function (t) {
if (t && this.targets[t.id]) {
this.activeTarget = this.targets[t.id];
this.activeTarget.el = t;
this.anchor = this.activeTarget.anchor;
if (this.anchor) {
this.anchorTarget = t;
}
this.delayShow();
return;
}
}
});
Eric24
16 Jun 2011, 11:37 AM
Pretty slick! Unfortunately, I do need the "random image shapes" (my specific application is actually to select geographic areas on a map of countries.
--Eric
Nigel
16 Jun 2011, 12:28 PM
Well, from a quick google search, this might be easier than I at first thought. I just found this page (http://alienryderflex.com/polygon/) which describes the maths for determining that a point is inside a polygon.
I won't get to this again until the weekend but I might have a crack at getting it working - for convenience, I reckon each hotspot should either be definable with the existing top/left/bottom/right, or with an array of points forming a polygon.
Views?
Nigel
Eric24
16 Jun 2011, 2:04 PM
Yes, I agree (if all you need is a rectangle, it would seem overly difficult to have to define it as a set of 4 vertexes). So a hotspot is either defined with top/bottom/left/right properties or a 'polygon' array property: [[3,6],[7,9],[13,28],...]
Although, a rectangle is essentially defined as two points (top/left and bottom/right), so maybe there's a special syntax for the polygon property of [top, left, bottom, right]. Just a thought--not fully baked.
Powered by vBulletin® Version 4.1.5 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.