Skip to content

Granular options for on-chart editing #1895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/components/annotations/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ function drawOne(gd, index) {
function drawRaw(gd, options, index, subplotId, xa, ya) {
var fullLayout = gd._fullLayout;
var gs = gd._fullLayout._size;
var edits = gd._context.edits;

var className;
var annbase;

Expand Down Expand Up @@ -128,8 +130,11 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
var annTextGroup = annGroup.append('g')
.classed('annotation-text-g', true);

var editTextPosition = edits[options.showarrow ? 'annotationTail' : 'annotationPosition'];
var textEvents = options.captureevents || edits.annotationText || editTextPosition;
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to address this now, but this seems like the right place to reference #1750


var annTextGroupInner = annTextGroup.append('g')
.style('pointer-events', options.captureevents ? 'all' : null)
.style('pointer-events', textEvents ? 'all' : null)
.call(setCursor, 'default')
.on('click', function() {
gd._dragging = false;
Expand Down Expand Up @@ -519,7 +524,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {

// the arrow dragger is a small square right at the head, then a line to the tail,
// all expanded by a stroke width of 6px plus the arrow line width
if(gd._context.editable && arrow.node().parentNode && !subplotId) {
if(edits.annotationPosition && arrow.node().parentNode && !subplotId) {
var arrowDragHeadX = headX;
var arrowDragHeadY = headY;
if(options.standoff) {
Expand Down Expand Up @@ -601,7 +606,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
if(options.showarrow) drawArrow(0, 0);

// user dragging the annotation (text, not arrow)
if(gd._context.editable) {
if(editTextPosition) {
var update,
baseTextTransform;

Expand Down Expand Up @@ -679,7 +684,7 @@ function drawRaw(gd, options, index, subplotId, xa, ya) {
}
}

if(gd._context.editable) {
if(edits.annotationText) {
annText.call(svgTextUtils.makeEditable, {delegate: annTextGroupInner, gd: gd})
.call(textLayout)
.on('edit', function(_text) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/colorbar/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ module.exports = function draw(gd, id) {
if(cbDone && cbDone.then) (gd._promises || []).push(cbDone);

// dragging...
if(gd._context.editable) {
if(gd._context.edits.colorbarPosition) {
var t0,
xf,
yf;
Expand Down
86 changes: 27 additions & 59 deletions src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ module.exports = function draw(gd) {
});
}

if(gd._context.editable) {
if(gd._context.edits.legendPosition) {
var xf, yf, x0, y0;

legend.classed('cursor-move', true);
Expand Down Expand Up @@ -385,7 +385,7 @@ function drawTexts(g, gd) {
});
}

if(gd._context.editable && !isPie) {
if(gd._context.edits.legendText && !isPie) {
text.call(svgTextUtils.makeEditable, {gd: gd})
.call(textLayout)
.on('edit', function(text) {
Expand Down Expand Up @@ -597,10 +597,15 @@ function computeTextDimensions(g, gd) {
}

function computeLegendDimensions(gd, groups, traces) {
var fullLayout = gd._fullLayout,
opts = fullLayout.legend,
borderwidth = opts.borderwidth,
isGrouped = helpers.isGrouped(opts);
var fullLayout = gd._fullLayout;
var opts = fullLayout.legend;
var borderwidth = opts.borderwidth;
var isGrouped = helpers.isGrouped(opts);

var extraWidth = 0;

opts.width = 0;
opts.height = 0;

if(helpers.isVertical(opts)) {
if(isGrouped) {
Expand All @@ -609,9 +614,6 @@ function computeLegendDimensions(gd, groups, traces) {
});
}

opts.width = 0;
opts.height = 0;

traces.each(function(d) {
var legendItem = d[0],
textHeight = legendItem.height,
Expand All @@ -632,26 +634,9 @@ function computeLegendDimensions(gd, groups, traces) {
opts.height += (opts._lgroupsLength - 1) * opts.tracegroupgap;
}

// make sure we're only getting full pixels
opts.width = Math.ceil(opts.width);
opts.height = Math.ceil(opts.height);

traces.each(function(d) {
var legendItem = d[0],
bg = d3.select(this).select('.legendtoggle');

bg.call(Drawing.setRect,
0,
-legendItem.height / 2,
(gd._context.editable ? 0 : opts.width) + 40,
legendItem.height
);
});
extraWidth = 40;
}
else if(isGrouped) {
opts.width = 0;
opts.height = 0;

var groupXOffsets = [opts.width],
groupData = groups.data();

Expand Down Expand Up @@ -692,26 +677,8 @@ function computeLegendDimensions(gd, groups, traces) {

opts.height += 10 + borderwidth * 2;
opts.width += borderwidth * 2;

// make sure we're only getting full pixels
opts.width = Math.ceil(opts.width);
opts.height = Math.ceil(opts.height);

traces.each(function(d) {
var legendItem = d[0],
bg = d3.select(this).select('.legendtoggle');

bg.call(Drawing.setRect,
0,
-legendItem.height / 2,
(gd._context.editable ? 0 : opts.width),
legendItem.height
);
});
}
else {
opts.width = 0;
opts.height = 0;
var rowHeight = 0,
maxTraceHeight = 0,
maxTraceWidth = 0,
Expand Down Expand Up @@ -750,22 +717,23 @@ function computeLegendDimensions(gd, groups, traces) {
opts.width += borderwidth * 2;
opts.height += 10 + borderwidth * 2;

// make sure we're only getting full pixels
opts.width = Math.ceil(opts.width);
opts.height = Math.ceil(opts.height);
}

traces.each(function(d) {
var legendItem = d[0],
bg = d3.select(this).select('.legendtoggle');
// make sure we're only getting full pixels
opts.width = Math.ceil(opts.width);
opts.height = Math.ceil(opts.height);

bg.call(Drawing.setRect,
0,
-legendItem.height / 2,
(gd._context.editable ? 0 : opts.width),
legendItem.height
);
});
}
traces.each(function(d) {
var legendItem = d[0],
bg = d3.select(this).select('.legendtoggle');

bg.call(Drawing.setRect,
Copy link
Contributor

Choose a reason for hiding this comment

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

lovely commit 🎉

0,
-legendItem.height / 2,
(gd._context.edits.legendText ? 0 : opts.width) + extraWidth,
legendItem.height
);
});
}

function expandMargin(gd) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/shapes/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ function drawOne(gd, index) {
null
);

if(gd._context.editable) setupDragElement(gd, path, options, index);
if(gd._context.edits.shapePosition) setupDragElement(gd, path, options, index);
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/components/titles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ Titles.draw = function(gd, titleClass, options) {
var opacity = 1;
var isplaceholder = false;
var txt = cont.title.trim();
var editable = gd._context.editable;

// only make this title editable if we positively identify its property
// as one that has editing enabled.
var editAttr;
if(prop === 'title') editAttr = 'titleText';
else if(prop.indexOf('axis') !== -1) editAttr = 'axisTitleText';
else if(prop.indexOf('colorbar' !== -1)) editAttr = 'colorbarTitleText';
var editable = gd._context.edits[editAttr];

if(txt === '') opacity = 0;
if(txt.match(PLACEHOLDER_RE)) {
Expand Down
37 changes: 33 additions & 4 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,28 +397,57 @@ function opaqueSetBackground(gd, bgColor) {
}

function setPlotContext(gd, config) {
if(!gd._context) gd._context = Lib.extendFlat({}, Plotly.defaultConfig);
if(!gd._context) gd._context = Lib.extendDeep({}, Plotly.defaultConfig);
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice. Maybe config isn't as poorly tested than I thought.

var context = gd._context;

var i, keys, key;

if(config) {
Object.keys(config).forEach(function(key) {
keys = Object.keys(config);
for(i = 0; i < keys.length; i++) {
key = keys[i];
if(key === 'editable' || key === 'edits') continue;
if(key in context) {
if(key === 'setBackground' && config[key] === 'opaque') {
context[key] = opaqueSetBackground;
}
else context[key] = config[key];
}
});
}

// map plot3dPixelRatio to plotGlPixelRatio for backward compatibility
if(config.plot3dPixelRatio && !context.plotGlPixelRatio) {
context.plotGlPixelRatio = context.plot3dPixelRatio;
}

// now deal with editable and edits - first editable overrides
// everything, then edits refines
var editable = config.editable;
if(editable !== undefined) {
// we're not going to *use* context.editable, we're only going to
// use context.edits... but keep it for the record
context.editable = editable;

keys = Object.keys(context.edits);
for(i = 0; i < keys.length; i++) {
context.edits[keys[i]] = editable;
}
}
if(config.edits) {
keys = Object.keys(config.edits);
for(i = 0; i < keys.length; i++) {
key = keys[i];
if(key in context.edits) {
context.edits[key] = config.edits[key];
}
}
}
}

// staticPlot forces a bunch of others:
if(context.staticPlot) {
context.editable = false;
context.edits = {};
context.autosizable = false;
context.scrollZoom = false;
context.doubleClick = false;
Expand Down Expand Up @@ -487,7 +516,7 @@ function plotPolar(gd, data, layout) {
var title = polarPlotSVG.select('.title-group text')
.call(titleLayout);

if(gd._context.editable) {
if(gd._context.edits.titleText) {
if(!txt || txt === placeholderText) {
opacity = 0.2;
// placeholder is not going through convertToTspans
Expand Down
21 changes: 20 additions & 1 deletion src/plot_api/plot_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,27 @@ module.exports = {
// no interactivity, for export or image generation
staticPlot: false,

// we can edit titles, move annotations, etc
// we can edit titles, move annotations, etc - sets all pieces of `edits`
// unless a separate `edits` config item overrides individual parts
editable: false,
edits: {
// annotationPosition: the main anchor of the annotation, which is the
// text (if no arrow) or the arrow (which drags the whole thing leaving
// the arrow length & direction unchanged)
annotationPosition: false,
// just for annotations with arrows, change the length and direction of the arrow
annotationTail: false,
annotationText: false,
axisTitleText: false,
colorbarPosition: false,
colorbarTitleText: false,
legendPosition: false,
// edit the trace name fields from the legend
legendText: false,
shapePosition: false,
// the global `layout.title`
titleText: false
},

// DO autosize once regardless of layout.autosize
// (use default width or height values otherwise)
Expand Down
Loading