Skip to content
8 changes: 8 additions & 0 deletions src/components/fx/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
else hovermodeDflt = 'closest';

coerce('hovermode', hovermodeDflt);

// if only mapbox subplots is present on graph,
// reset 'zoom' dragmode to 'pan' until 'zoom' is implemented,
// so that the correct modebar button is active
if(layoutOut._has('mapbox') && layoutOut._basePlotModules.length === 1 &&
layoutOut.dragmode === 'zoom') {
layoutOut.dragmode = 'pan';
}
};

function isHoriz(fullData) {
Expand Down
11 changes: 8 additions & 3 deletions src/components/modebar/manage.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

var Axes = require('../../plots/cartesian/axes');
var scatterSubTypes = require('../../traces/scatter/subtypes');
var Registry = require('../../registry');

var createModeBar = require('./modebar');
var modeBarButtons = require('./buttons');
Expand Down Expand Up @@ -78,7 +79,8 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
hasGeo = fullLayout._has('geo'),
hasPie = fullLayout._has('pie'),
hasGL2D = fullLayout._has('gl2d'),
hasTernary = fullLayout._has('ternary');
hasTernary = fullLayout._has('ternary'),
hasMapbox = fullLayout._has('mapbox');

var groups = [];

Expand Down Expand Up @@ -121,7 +123,10 @@ function getButtonGroups(gd, buttonsToRemove, buttonsToAdd) {
if(((hasCartesian || hasGL2D) && !allAxesFixed) || hasTernary) {
dragModeGroup = ['zoom2d', 'pan2d'];
}
if((hasCartesian || hasTernary || hasGL2D) && isSelectable(fullData)) {
if(hasMapbox) {
dragModeGroup = ['pan2d'];
}
if(isSelectable(fullData)) {
dragModeGroup.push('select2d');
dragModeGroup.push('lasso2d');
}
Expand Down Expand Up @@ -173,7 +178,7 @@ function isSelectable(fullData) {

if(!trace._module || !trace._module.selectPoints) continue;

if(trace.type === 'scatter' || trace.type === 'scatterternary' || trace.type === 'scattergl') {
if(Registry.traceIs(trace, 'scatter-like')) {
if(scatterSubTypes.hasMarkers(trace) || scatterSubTypes.hasText(trace)) {
selectable = true;
}
Expand Down
5 changes: 4 additions & 1 deletion src/constants/interactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,8 @@ module.exports = {

// ms between first mousedown and 2nd mouseup to constitute dblclick...
// we don't seem to have access to the system setting
DBLCLICKDELAY: 300
DBLCLICKDELAY: 300,

// opacity dimming fraction for points that are not in selection
DESELECTDIM: 0.2
};
2 changes: 1 addition & 1 deletion src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ lib.minExtend = function(obj1, obj2) {
for(i = 0; i < keys.length; i++) {
k = keys[i];
v = obj1[k];
if(k.charAt(0) === '_' || typeof v === 'function' || k === 'glTrace') continue;
if(k.charAt(0) === '_' || typeof v === 'function') continue;
else if(k === 'module') objOut[k] = v;
else if(Array.isArray(v)) objOut[k] = v.slice(0, arrayLen);
else if(v && (typeof v === 'object')) objOut[k] = lib.minExtend(obj1[k], obj2[k]);
Expand Down
16 changes: 11 additions & 5 deletions src/plot_api/subroutines.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,21 +378,27 @@ exports.doTicksRelayout = function(gd) {

exports.doModeBar = function(gd) {
var fullLayout = gd._fullLayout;
var subplotIds, scene, i;
var subplotIds, subplotObj, i;

ModeBar.manage(gd);
initInteractions(gd);

subplotIds = Plots.getSubplotIds(fullLayout, 'gl3d');
for(i = 0; i < subplotIds.length; i++) {
scene = fullLayout[subplotIds[i]]._scene;
scene.updateFx(fullLayout.dragmode, fullLayout.hovermode);
subplotObj = fullLayout[subplotIds[i]]._scene;
subplotObj.updateFx(fullLayout.dragmode, fullLayout.hovermode);
}

subplotIds = Plots.getSubplotIds(fullLayout, 'gl2d');
for(i = 0; i < subplotIds.length; i++) {
scene = fullLayout._plots[subplotIds[i]]._scene2d;
scene.updateFx(fullLayout.dragmode);
subplotObj = fullLayout._plots[subplotIds[i]]._scene2d;
subplotObj.updateFx(fullLayout.dragmode);
}

subplotIds = Plots.getSubplotIds(fullLayout, 'mapbox');
for(i = 0; i < subplotIds.length; i++) {
subplotObj = fullLayout[subplotIds[i]]._subplot;
subplotObj.updateFx(fullLayout);
}

return Plots.previousPromises(gd);
Expand Down
5 changes: 0 additions & 5 deletions src/plots/cartesian/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,6 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
oldFullLayout._infolayer.select('.' + axIds[i] + 'title').remove();
}
}

// clean selection
if(oldFullLayout._zoomlayer) {
oldFullLayout._zoomlayer.selectAll('.select-outline').remove();
}
};

exports.drawFramework = function(gd) {
Expand Down
64 changes: 39 additions & 25 deletions src/plots/cartesian/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ function getAxId(ax) { return ax._id; }
module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
var zoomLayer = dragOptions.gd._fullLayout._zoomlayer,
dragBBox = dragOptions.element.getBoundingClientRect(),
xs = dragOptions.plotinfo.xaxis._offset,
ys = dragOptions.plotinfo.yaxis._offset,
plotinfo = dragOptions.plotinfo,
xs = plotinfo.xaxis._offset,
ys = plotinfo.yaxis._offset,
x0 = startX - dragBBox.left,
y0 = startY - dragBBox.top,
x1 = x0,
Expand Down Expand Up @@ -71,6 +72,7 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
searchInfo,
selection = [],
eventData;

for(i = 0; i < gd.calcdata.length; i++) {
cd = gd.calcdata[i];
trace = cd[0].trace;
Expand Down Expand Up @@ -106,9 +108,41 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {

function ascending(a, b) { return a - b; }

// allow subplots to override fillRangeItems routine
var fillRangeItems;

if(plotinfo.fillRangeItems) {
fillRangeItems = plotinfo.fillRangeItems;
} else {
if(mode === 'select') {
fillRangeItems = function(eventData, poly) {
var ranges = eventData.range = {};

for(i = 0; i < allAxes.length; i++) {
var ax = allAxes[i];
var axLetter = ax._id.charAt(0);

ranges[ax._id] = [
ax.p2d(poly[axLetter + 'min']),
ax.p2d(poly[axLetter + 'max'])
].sort(ascending);
}
};
} else {
fillRangeItems = function(eventData, poly, pts) {
var dataPts = eventData.lassoPoints = {};

for(i = 0; i < allAxes.length; i++) {
var ax = allAxes[i];
dataPts[ax._id] = pts.filtered.map(axValue(ax));
}
};
}
}

dragOptions.moveFn = function(dx0, dy0) {
var poly,
ax;
var poly;

x1 = Math.max(0, Math.min(pw, dx0 + x0));
y1 = Math.max(0, Math.min(ph, dy0 + y0));

Expand Down Expand Up @@ -158,27 +192,7 @@ module.exports = function prepSelect(e, startX, startY, dragOptions, mode) {
}

eventData = {points: selection};

if(mode === 'select') {
var ranges = eventData.range = {},
axLetter;

for(i = 0; i < allAxes.length; i++) {
ax = allAxes[i];
axLetter = ax._id.charAt(0);
ranges[ax._id] = [
ax.p2d(poly[axLetter + 'min']),
ax.p2d(poly[axLetter + 'max'])].sort(ascending);
}
}
else {
var dataPts = eventData.lassoPoints = {};

for(i = 0; i < allAxes.length; i++) {
ax = allAxes[i];
dataPts[ax._id] = pts.filtered.map(axValue(ax));
}
}
fillRangeItems(eventData, poly, pts);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, probably we have to merge this before I continue multiselect, because I depend on this part of code a lot.

dragOptions.gd.emit('plotly_selecting', eventData);
};

Expand Down
78 changes: 74 additions & 4 deletions src/plots/mapbox/mapbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ var mapboxgl = require('mapbox-gl');

var Fx = require('../../components/fx');
var Lib = require('../../lib');
var dragElement = require('../../components/dragelement');
var prepSelect = require('../cartesian/select');
var constants = require('./constants');
var layoutAttributes = require('./layout_attributes');
var createMapboxLayer = require('./layers');
Expand Down Expand Up @@ -86,9 +88,9 @@ proto.plot = function(calcData, fullLayout, promises) {
};

proto.createMap = function(calcData, fullLayout, resolve, reject) {
var self = this,
gd = self.gd,
opts = self.opts;
var self = this;
var gd = self.gd;
var opts = self.opts;

// store style id and URL or object
var styleObj = self.styleObj = getStyleObj(opts.style);
Expand All @@ -107,7 +109,9 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
pitch: opts.pitch,

interactive: !self.isStatic,
preserveDrawingBuffer: self.isStatic
preserveDrawingBuffer: self.isStatic,

boxZoom: false
});

// clear navigation container
Expand All @@ -128,6 +132,8 @@ proto.createMap = function(calcData, fullLayout, resolve, reject) {
self.resolveOnRender(resolve);
});

if(self.isStatic) return;

// keep track of pan / zoom in user layout and emit relayout event
map.on('moveend', function(eventData) {
if(!self.map) return;
Expand Down Expand Up @@ -261,6 +267,7 @@ proto.updateLayout = function(fullLayout) {

this.updateLayers();
this.updateFramework(fullLayout);
this.updateFx(fullLayout);
this.map.resize();
};

Expand Down Expand Up @@ -314,6 +321,69 @@ proto.createFramework = function(fullLayout) {
self.updateFramework(fullLayout);
};

proto.updateFx = function(fullLayout) {
var self = this;
var map = self.map;
var gd = self.gd;

if(self.isStatic) return;

function invert(pxpy) {
var obj = self.map.unproject(pxpy);
return [obj.lng, obj.lat];
}

var dragMode = fullLayout.dragmode;
var fillRangeItems;

if(dragMode === 'select') {
fillRangeItems = function(eventData, poly) {
var ranges = eventData.range = {};
ranges[self.id] = [
invert([poly.xmin, poly.ymin]),
invert([poly.xmax, poly.ymax])
];
};
} else {
fillRangeItems = function(eventData, poly, pts) {
var dataPts = eventData.lassoPoints = {};
dataPts[self.id] = pts.filtered.map(invert);
};
}

if(dragMode === 'select' || dragMode === 'lasso') {
map.dragPan.disable();

var dragOptions = {
element: self.div,
gd: gd,
plotinfo: {
xaxis: self.xaxis,
yaxis: self.yaxis,
fillRangeItems: fillRangeItems
},
xaxes: [self.xaxis],
yaxes: [self.yaxis],
subplot: self.id
};

dragOptions.prepFn = function(e, startX, startY) {
prepSelect(e, startX, startY, dragOptions, dragMode);
};

dragOptions.doneFn = function(dragged, numClicks) {
if(numClicks === 2) {
fullLayout._zoomlayer.selectAll('.select-outline').remove();
}
};

dragElement.init(dragOptions);
} else {
map.dragPan.enable();
self.div.onmousedown = null;
}
};

proto.updateFramework = function(fullLayout) {
var domain = fullLayout[this.id].domain,
size = fullLayout._size;
Expand Down
4 changes: 4 additions & 0 deletions src/plots/plots.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,10 @@ plots.cleanPlot = function(newFullData, newFullLayout, oldFullData, oldFullLayou
.selectAll(query).remove();
}
}

if(oldFullLayout._zoomlayer) {
oldFullLayout._zoomlayer.selectAll('.select-outline').remove();
}
};

plots.linkSubplots = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
Expand Down
4 changes: 0 additions & 4 deletions src/plots/ternary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,4 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
oldTernary.clipDef.remove();
}
}

if(oldFullLayout._zoomlayer) {
oldFullLayout._zoomlayer.selectAll('.select-outline').remove();
}
};
2 changes: 1 addition & 1 deletion src/traces/scatter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Scatter.animatable = true;
Scatter.moduleType = 'trace';
Scatter.name = 'scatter';
Scatter.basePlotModule = require('../../plots/cartesian');
Scatter.categories = ['cartesian', 'symbols', 'markerColorscale', 'errorBarsOK', 'showLegend'];
Scatter.categories = ['cartesian', 'symbols', 'markerColorscale', 'errorBarsOK', 'showLegend', 'scatter-like'];
Scatter.meta = {
description: [
'The scatter trace type encompasses line charts, scatter charts, text charts, and bubble charts.',
Expand Down
3 changes: 1 addition & 2 deletions src/traces/scatter/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
'use strict';

var subtypes = require('./subtypes');

var DESELECTDIM = 0.2;
var DESELECTDIM = require('../../constants/interactions').DESELECTDIM;

module.exports = function selectPoints(searchInfo, polygon) {
var cd = searchInfo.cd,
Expand Down
6 changes: 3 additions & 3 deletions src/traces/scattergl/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ var makeBubbleSizeFn = require('../scatter/make_bubble_size_func');
var getTraceColor = require('../scatter/get_trace_color');
var MARKER_SYMBOLS = require('../../constants/gl2d_markers');
var DASHES = require('../../constants/gl2d_dashes');
var DESELECTDIM = require('../../constants/interactions').DESELECTDIM;

var AXES = ['xaxis', 'yaxis'];
var DESELECTDIM = 0.2;
var TRANSPARENT = [0, 0, 0, 0];

function LineWithMarkers(scene, uid) {
Expand Down Expand Up @@ -322,8 +322,8 @@ proto.update = function(options, cdscatter) {
this.color = getTraceColor(options, {});

// provide reference for selecting points
if(cdscatter && cdscatter[0] && !cdscatter[0].glTrace) {
cdscatter[0].glTrace = this;
if(cdscatter && cdscatter[0] && !cdscatter[0]._glTrace) {
cdscatter[0]._glTrace = this;
}
};

Expand Down
Loading