1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | (function($) {
|
28 | 'use strict';
|
29 |
|
30 | var options = {
|
31 | grid: {
|
32 | hoverable: false,
|
33 | clickable: false
|
34 | }
|
35 | };
|
36 |
|
37 | var browser = $.plot.browser;
|
38 |
|
39 | var eventType = {
|
40 | click: 'click',
|
41 | hover: 'hover'
|
42 | }
|
43 |
|
44 | function init(plot) {
|
45 | var lastMouseMoveEvent;
|
46 | var highlights = [];
|
47 |
|
48 | function bindEvents(plot, eventHolder) {
|
49 | var o = plot.getOptions();
|
50 |
|
51 | if (o.grid.hoverable || o.grid.clickable) {
|
52 | eventHolder[0].addEventListener('touchevent', triggerCleanupEvent, false);
|
53 | eventHolder[0].addEventListener('tap', generatePlothoverEvent, false);
|
54 | }
|
55 |
|
56 | if (o.grid.clickable) {
|
57 | eventHolder.bind("click", onClick);
|
58 | }
|
59 |
|
60 | if (o.grid.hoverable) {
|
61 | eventHolder.bind("mousemove", onMouseMove);
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | eventHolder.bind("mouseleave", onMouseLeave);
|
70 | }
|
71 | }
|
72 |
|
73 | function shutdown(plot, eventHolder) {
|
74 | eventHolder[0].removeEventListener('tap', generatePlothoverEvent);
|
75 | eventHolder[0].removeEventListener('touchevent', triggerCleanupEvent);
|
76 | eventHolder.unbind("mousemove", onMouseMove);
|
77 | eventHolder.unbind("mouseleave", onMouseLeave);
|
78 | eventHolder.unbind("click", onClick);
|
79 | highlights = [];
|
80 | }
|
81 |
|
82 |
|
83 | function generatePlothoverEvent(e) {
|
84 | var o = plot.getOptions(),
|
85 | newEvent = new CustomEvent('mouseevent');
|
86 |
|
87 |
|
88 | newEvent.pageX = e.detail.changedTouches[0].pageX;
|
89 | newEvent.pageY = e.detail.changedTouches[0].pageY;
|
90 | newEvent.clientX = e.detail.changedTouches[0].clientX;
|
91 | newEvent.clientY = e.detail.changedTouches[0].clientY;
|
92 |
|
93 | if (o.grid.hoverable) {
|
94 | doTriggerClickHoverEvent(newEvent, eventType.hover, 30);
|
95 | }
|
96 | return false;
|
97 | }
|
98 |
|
99 | function doTriggerClickHoverEvent(event, eventType, searchDistance) {
|
100 | var series = plot.getData();
|
101 | if (event !== undefined
|
102 | && series.length > 0
|
103 | && series[0].xaxis.c2p !== undefined
|
104 | && series[0].yaxis.c2p !== undefined) {
|
105 | var eventToTrigger = "plot" + eventType;
|
106 | var seriesFlag = eventType + "able";
|
107 | triggerClickHoverEvent(eventToTrigger, event,
|
108 | function(i) {
|
109 | return series[i][seriesFlag] !== false;
|
110 | }, searchDistance);
|
111 | }
|
112 | }
|
113 |
|
114 | function onMouseMove(e) {
|
115 | lastMouseMoveEvent = e;
|
116 | plot.getPlaceholder()[0].lastMouseMoveEvent = e;
|
117 | doTriggerClickHoverEvent(e, eventType.hover);
|
118 | }
|
119 |
|
120 | function onMouseLeave(e) {
|
121 | lastMouseMoveEvent = undefined;
|
122 | plot.getPlaceholder()[0].lastMouseMoveEvent = undefined;
|
123 | triggerClickHoverEvent("plothover", e,
|
124 | function(i) {
|
125 | return false;
|
126 | });
|
127 | }
|
128 |
|
129 | function onClick(e) {
|
130 | doTriggerClickHoverEvent(e, eventType.click);
|
131 | }
|
132 |
|
133 | function triggerCleanupEvent() {
|
134 | plot.unhighlight();
|
135 | plot.getPlaceholder().trigger('plothovercleanup');
|
136 | }
|
137 |
|
138 |
|
139 |
|
140 | function triggerClickHoverEvent(eventname, event, seriesFilter, searchDistance) {
|
141 | var options = plot.getOptions(),
|
142 | offset = plot.offset(),
|
143 | page = browser.getPageXY(event),
|
144 | canvasX = page.X - offset.left,
|
145 | canvasY = page.Y - offset.top,
|
146 | pos = plot.c2p({
|
147 | left: canvasX,
|
148 | top: canvasY
|
149 | }),
|
150 | distance = searchDistance !== undefined ? searchDistance : options.grid.mouseActiveRadius;
|
151 |
|
152 | pos.pageX = page.X;
|
153 | pos.pageY = page.Y;
|
154 |
|
155 | var item = plot.findNearbyItem(canvasX, canvasY, seriesFilter, distance);
|
156 |
|
157 | if (item) {
|
158 |
|
159 | item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left, 10);
|
160 | item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top, 10);
|
161 | }
|
162 |
|
163 | if (options.grid.autoHighlight) {
|
164 |
|
165 | for (var i = 0; i < highlights.length; ++i) {
|
166 | var h = highlights[i];
|
167 | if ((h.auto === eventname &&
|
168 | !(item && h.series === item.series &&
|
169 | h.point[0] === item.datapoint[0] &&
|
170 | h.point[1] === item.datapoint[1])) || !item) {
|
171 | unhighlight(h.series, h.point);
|
172 | }
|
173 | }
|
174 |
|
175 | if (item) {
|
176 | highlight(item.series, item.datapoint, eventname);
|
177 | }
|
178 | }
|
179 |
|
180 | plot.getPlaceholder().trigger(eventname, [pos, item]);
|
181 | }
|
182 |
|
183 | function highlight(s, point, auto) {
|
184 | if (typeof s === "number") {
|
185 | s = plot.getData()[s];
|
186 | }
|
187 |
|
188 | if (typeof point === "number") {
|
189 | var ps = s.datapoints.pointsize;
|
190 | point = s.datapoints.points.slice(ps * point, ps * (point + 1));
|
191 | }
|
192 |
|
193 | var i = indexOfHighlight(s, point);
|
194 | if (i === -1) {
|
195 | highlights.push({
|
196 | series: s,
|
197 | point: point,
|
198 | auto: auto
|
199 | });
|
200 |
|
201 | plot.triggerRedrawOverlay();
|
202 | } else if (!auto) {
|
203 | highlights[i].auto = false;
|
204 | }
|
205 | }
|
206 |
|
207 | function unhighlight(s, point) {
|
208 | if (s == null && point == null) {
|
209 | highlights = [];
|
210 | plot.triggerRedrawOverlay();
|
211 | return;
|
212 | }
|
213 |
|
214 | if (typeof s === "number") {
|
215 | s = plot.getData()[s];
|
216 | }
|
217 |
|
218 | if (typeof point === "number") {
|
219 | var ps = s.datapoints.pointsize;
|
220 | point = s.datapoints.points.slice(ps * point, ps * (point + 1));
|
221 | }
|
222 |
|
223 | var i = indexOfHighlight(s, point);
|
224 | if (i !== -1) {
|
225 | highlights.splice(i, 1);
|
226 |
|
227 | plot.triggerRedrawOverlay();
|
228 | }
|
229 | }
|
230 |
|
231 | function indexOfHighlight(s, p) {
|
232 | for (var i = 0; i < highlights.length; ++i) {
|
233 | var h = highlights[i];
|
234 | if (h.series === s &&
|
235 | h.point[0] === p[0] &&
|
236 | h.point[1] === p[1]) {
|
237 | return i;
|
238 | }
|
239 | }
|
240 |
|
241 | return -1;
|
242 | }
|
243 |
|
244 | function processDatapoints() {
|
245 | triggerCleanupEvent();
|
246 | doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover);
|
247 | }
|
248 |
|
249 | function setupGrid() {
|
250 | doTriggerClickHoverEvent(lastMouseMoveEvent, eventType.hover);
|
251 | }
|
252 |
|
253 | function drawOverlay(plot, octx, overlay) {
|
254 | var plotOffset = plot.getPlotOffset(),
|
255 | i, hi;
|
256 |
|
257 | octx.save();
|
258 | octx.translate(plotOffset.left, plotOffset.top);
|
259 | for (i = 0; i < highlights.length; ++i) {
|
260 | hi = highlights[i];
|
261 |
|
262 | if (hi.series.bars.show) drawBarHighlight(hi.series, hi.point, octx);
|
263 | else drawPointHighlight(hi.series, hi.point, octx, plot);
|
264 | }
|
265 | octx.restore();
|
266 | }
|
267 |
|
268 | function drawPointHighlight(series, point, octx, plot) {
|
269 | var x = point[0],
|
270 | y = point[1],
|
271 | axisx = series.xaxis,
|
272 | axisy = series.yaxis,
|
273 | highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();
|
274 |
|
275 | if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
|
276 | return;
|
277 | }
|
278 |
|
279 | var pointRadius = series.points.radius + series.points.lineWidth / 2;
|
280 | octx.lineWidth = pointRadius;
|
281 | octx.strokeStyle = highlightColor;
|
282 | var radius = 1.5 * pointRadius;
|
283 | x = axisx.p2c(x);
|
284 | y = axisy.p2c(y);
|
285 |
|
286 | octx.beginPath();
|
287 | var symbol = series.points.symbol;
|
288 | if (symbol === 'circle') {
|
289 | octx.arc(x, y, radius, 0, 2 * Math.PI, false);
|
290 | } else if (typeof symbol === 'string' && plot.drawSymbol && plot.drawSymbol[symbol]) {
|
291 | plot.drawSymbol[symbol](octx, x, y, radius, false);
|
292 | }
|
293 |
|
294 | octx.closePath();
|
295 | octx.stroke();
|
296 | }
|
297 |
|
298 | function drawBarHighlight(series, point, octx) {
|
299 | var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
|
300 | fillStyle = highlightColor,
|
301 | barLeft;
|
302 |
|
303 | var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
|
304 | switch (series.bars.align) {
|
305 | case "left":
|
306 | barLeft = 0;
|
307 | break;
|
308 | case "right":
|
309 | barLeft = -barWidth;
|
310 | break;
|
311 | default:
|
312 | barLeft = -barWidth / 2;
|
313 | }
|
314 |
|
315 | octx.lineWidth = series.bars.lineWidth;
|
316 | octx.strokeStyle = highlightColor;
|
317 |
|
318 | var fillTowards = series.bars.fillTowards || 0,
|
319 | bottom = fillTowards > series.yaxis.min ? Math.min(series.yaxis.max, fillTowards) : series.yaxis.min;
|
320 |
|
321 | $.plot.drawSeries.drawBar(point[0], point[1], point[2] || bottom, barLeft, barLeft + barWidth,
|
322 | function() {
|
323 | return fillStyle;
|
324 | }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
|
325 | }
|
326 |
|
327 | function initHover(plot, options) {
|
328 | plot.highlight = highlight;
|
329 | plot.unhighlight = unhighlight;
|
330 | if (options.grid.hoverable || options.grid.clickable) {
|
331 | plot.hooks.drawOverlay.push(drawOverlay);
|
332 | plot.hooks.processDatapoints.push(processDatapoints);
|
333 | plot.hooks.setupGrid.push(setupGrid);
|
334 | }
|
335 |
|
336 | lastMouseMoveEvent = plot.getPlaceholder()[0].lastMouseMoveEvent;
|
337 | }
|
338 |
|
339 | plot.hooks.bindEvents.push(bindEvents);
|
340 | plot.hooks.shutdown.push(shutdown);
|
341 | plot.hooks.processOptions.push(initHover);
|
342 | }
|
343 |
|
344 | $.plot.plugins.push({
|
345 | init: init,
|
346 | options: options,
|
347 | name: 'hover',
|
348 | version: '0.1'
|
349 | });
|
350 | })(jQuery);
|