Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 65279d9

Browse files
committed
first pass hover labels!
1 parent 6706d37 commit 65279d9

File tree

4 files changed

+190
-22
lines changed

4 files changed

+190
-22
lines changed

src/plots/mapbox/mapbox.js

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
var mapboxgl = require('mapbox-gl');
1313

14+
var Fx = require('../cartesian/graph_interact');
1415
var constants = require('./constants');
15-
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
1616

1717

1818
function Mapbox(opts) {
@@ -31,7 +31,8 @@ function Mapbox(opts) {
3131

3232
// create framework on instantiation for a smoother first plot call
3333
this.div = null;
34-
this.hoverLayer = null;
34+
this.xaxis = null;
35+
this.yaxis = null;
3536
this.createFramework(fullLayout);
3637

3738
this.map = null;
@@ -70,7 +71,8 @@ proto.plot = function(fullData, fullLayout, promises) {
7071

7172
proto.createMap = function(fullData, fullLayout, resolve) {
7273
var self = this,
73-
opts = this.opts;
74+
gd = self.gd,
75+
opts = self.opts;
7476

7577
var map = self.map = new mapboxgl.Map({
7678
container: self.div,
@@ -104,10 +106,28 @@ proto.createMap = function(fullData, fullLayout, resolve) {
104106
opts._input.zoom = opts.zoom = map.getZoom();
105107
});
106108

109+
map.on('mousemove', function(evt) {
110+
var bb = self.div.getBoundingClientRect();
111+
112+
// some hackery to get Fx.hover to work
113+
114+
evt.clientX = evt.point.x + bb.left;
115+
evt.clientY = evt.point.y + bb.top;
107116

108-
// TODO hover labels
109-
map.on('mousemove', function() {});
117+
evt.target.getBoundingClientRect = function() { return bb; };
110118

119+
self.xaxis.p2c = function() { return evt.lngLat.lng; };
120+
self.yaxis.p2c = function() { return evt.lngLat.lat; };
121+
122+
Fx.hover(gd, evt, self.id);
123+
});
124+
125+
function unhover() {
126+
Fx.loneUnhover(fullLayout._toppaper);
127+
}
128+
129+
map.on('dragstart', unhover);
130+
map.on('zoomstart', unhover);
111131
};
112132

113133
proto.updateMap = function(fullData, fullLayout, resolve) {
@@ -185,27 +205,28 @@ proto.updateLayout = function(fullLayout) {
185205
};
186206

187207
proto.createFramework = function(fullLayout) {
188-
var div = this.div = document.createElement('div');
208+
var self = this;
189209

190-
div.id = this.uid;
210+
var div = self.div = document.createElement('div');
211+
212+
div.id = self.uid;
191213
div.style.position = 'absolute';
192214

193-
var hoverLayer = this.hoverLayer = document.createElementNS(
194-
xmlnsNamespaces.svg, 'svg'
195-
);
215+
self.container.appendChild(div);
196216

197-
var hoverStyle = hoverLayer.style;
217+
// create mock x/y axes for hover routine
198218

199-
hoverStyle.position = 'absolute';
200-
hoverStyle.top = hoverStyle.left = '0px';
201-
hoverStyle.width = hoverStyle.height = '100%';
202-
hoverStyle['z-index'] = 20;
203-
hoverStyle['pointer-events'] = 'none';
219+
self.xaxis = {
220+
_id: 'x',
221+
c2p: function(v) { return self.project(v).x; }
222+
};
204223

205-
this.container.appendChild(div);
206-
this.container.appendChild(hoverLayer);
224+
self.yaxis = {
225+
_id: 'y',
226+
c2p: function(v) { return self.project(v).y; }
227+
};
207228

208-
this.updateFramework(fullLayout);
229+
self.updateFramework(fullLayout);
209230
};
210231

211232
proto.updateFramework = function(fullLayout) {
@@ -214,18 +235,23 @@ proto.updateFramework = function(fullLayout) {
214235

215236
var style = this.div.style;
216237

217-
// Is this correct? It seems to get the map zoom level wrong?
238+
// TODO Is this correct? It seems to get the map zoom level wrong?
218239

219240
style.width = size.w * (domain.x[1] - domain.x[0]) + 'px';
220241
style.height = size.h * (domain.y[1] - domain.y[0]) + 'px';
221242
style.left = size.l + domain.x[0] * size.w + 'px';
222243
style.top = size.t + (1 - domain.y[1]) * size.h + 'px';
244+
245+
this.xaxis._offset = size.l + domain.x[0] * size.w;
246+
this.xaxis._length = size.w * (domain.x[1] - domain.x[0]);
247+
248+
this.yaxis._offset = size.t + (1 - domain.y[1]) * size.h;
249+
this.yaxis._length = size.h * (domain.y[1] - domain.y[0]);
223250
};
224251

225252
proto.destroy = function() {
226253
this.map.remove();
227254
this.container.removeChild(this.div);
228-
this.container.removeChild(this.hoverLayer);
229255
};
230256

231257
proto.toImage = function() {
@@ -255,6 +281,11 @@ proto.createGeoJSONSource = function() {
255281
return new mapboxgl.GeoJSONSource({data: blank});
256282
};
257283

284+
// convenience method to project a [lon, lat] array to pixel coords
285+
proto.project = function(v) {
286+
return this.map.project(new mapboxgl.LngLat(v[0], v[1]));
287+
};
288+
258289
function convertStyleUrl(style) {
259290
return constants.styleUrlPrefix + style + '-' + constants.styleUrlSuffix;
260291
}

src/traces/scattermapbox/calc.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var subtypes = require('../scatter/subtypes');
13+
var arrayToCalcItem = require('../../lib/array_to_calc_item');
14+
var calcMarkerColorscale = require('../scatter/marker_colorscale_calc');
15+
16+
17+
module.exports = function calc(gd, trace) {
18+
var len = trace.lon.length,
19+
hasMarkers = subtypes.hasMarkers(trace);
20+
21+
var cd = new Array(len);
22+
23+
for(var i = 0; i < len; i++) {
24+
var cdi = cd[i] = {};
25+
26+
cdi.lonlat = [trace.lon[i], trace.lat[i]];
27+
28+
if(hasMarkers) {
29+
var marker = trace.marker;
30+
31+
arrayToCalcItem(marker.color, cdi, 'mc', i);
32+
arrayToCalcItem(marker.size, cdi, 'ms', i);
33+
34+
// TODO handle these for hover !!!
35+
// arrayToCalcItem(colorScaleFn(marker.color), cdi, 'mcc', i);
36+
// arrayToCalcItem(sizFn(marker.size), cdi, 'mrc', i);
37+
}
38+
39+
arrayToCalcItem(trace.text, cdi, 'tx', i);
40+
}
41+
42+
calcMarkerColorscale(trace);
43+
44+
return cd;
45+
};

src/traces/scattermapbox/hover.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Copyright 2012-2016, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var Fx = require('../../plots/cartesian/graph_interact');
13+
var getTraceColor = require('../scatter/get_trace_color');
14+
15+
16+
module.exports = function hoverPoints(pointData, xval, yval) {
17+
var cd = pointData.cd,
18+
trace = cd[0].trace,
19+
xa = pointData.xa,
20+
ya = pointData.ya;
21+
22+
// compute winding number about [-180, 180] globe
23+
var winding = (xval >= 0) ?
24+
Math.floor((xval + 180) / 360) :
25+
Math.ceil((xval - 180) / 360);
26+
27+
// shift longitude to [-180, 180] to determine closest point
28+
var lonShift = winding * 360;
29+
var xval2 = xval - lonShift;
30+
31+
function distFn(d) {
32+
var lonlat = d.lonlat,
33+
dx = Math.abs(xa.c2p(lonlat) - xa.c2p([xval2, lonlat[1]])),
34+
dy = Math.abs(ya.c2p(lonlat) - ya.c2p([lonlat[0], yval])),
35+
rad = Math.max(3, d.mrc || 0);
36+
37+
return Math.max(Math.sqrt(dx * dx + dy * dy) - rad, 1 - 3 / rad);
38+
}
39+
40+
Fx.getClosest(cd, distFn, pointData);
41+
42+
// skip the rest (for this trace) if we didn't find a close point
43+
if(pointData.index === false) return;
44+
45+
var di = cd[pointData.index],
46+
lonlat = di.lonlat,
47+
lonlatShifted = [lonlat[0] + lonShift, lonlat[1]];
48+
49+
// shift labels back to original winded globe
50+
var xc = xa.c2p(lonlatShifted),
51+
yc = ya.c2p(lonlatShifted),
52+
rad = di.mrc || 1;
53+
54+
pointData.x0 = xc - rad;
55+
pointData.x1 = xc + rad;
56+
pointData.y0 = yc - rad;
57+
pointData.y1 = yc + rad;
58+
59+
pointData.color = getTraceColor(trace, di);
60+
pointData.extraText = getExtraText(trace, di);
61+
62+
return [pointData];
63+
};
64+
65+
function getExtraText(trace, di) {
66+
var hoverinfo = trace.hoverinfo.split('+'),
67+
isAll = (hoverinfo.indexOf('all') !== -1),
68+
hasLon = (hoverinfo.indexOf('lon') !== -1),
69+
hasLat = (hoverinfo.indexOf('lat') !== -1);
70+
71+
var lonlat = di.lonlat,
72+
text = [];
73+
74+
// TODO should we use a mock axis to format hover?
75+
// If so, we'll need to make precision be zoom-level dependent
76+
function format(v) {
77+
return v + '\u00B0';
78+
}
79+
80+
if(isAll || (hasLon && hasLat)) {
81+
text.push('(' + format(lonlat[0]) + ', ' + format(lonlat[1]) + ')');
82+
}
83+
else if(hasLon) text.push('lon: ' + format(lonlat[0]));
84+
else if(hasLat) text.push('lat: ' + format(lonlat[1]));
85+
86+
if(isAll || hoverinfo.indexOf('text') !== -1) {
87+
text.push(di.tx || trace.text);
88+
}
89+
90+
return text.join('<br>');
91+
}

src/traces/scattermapbox/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ var ScatterMapbox = {};
2222
ScatterMapbox.attributes = require('./attributes');
2323
ScatterMapbox.supplyDefaults = require('./defaults');
2424
ScatterMapbox.colorbar = require('../scatter/colorbar');
25-
ScatterMapbox.calc = require('../scattergeo/calc');
25+
ScatterMapbox.calc = require('./calc');
26+
ScatterMapbox.hoverPoints = require('./hover');
2627
ScatterMapbox.plot = require('./plot');
2728

2829
ScatterMapbox.moduleType = 'trace';

0 commit comments

Comments
 (0)