Skip to content

Apply and ensure stroke event only to activate editable shapes #4810

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 3 commits into from
May 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 9 additions & 8 deletions src/components/shapes/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ function drawOne(gd, index) {
var lineColor = options.line.width ? options.line.color : 'rgba(0,0,0,0)';
var lineWidth = options.line.width;
var lineDash = options.line.dash;
if(!lineWidth && options.editable === true) {
// ensure invisible border to active the shape
lineWidth = 5;
lineDash = 'solid';
}

var isOpen = d[d.length - 1] !== 'Z';

Expand Down Expand Up @@ -163,15 +168,11 @@ function drawOne(gd, index) {
} else {
if(gd._context.edits.shapePosition) {
setupDragElement(gd, path, options, index, shapeLayer, editHelpers);
} else {
if(options.editable === true) {
path.style('pointer-events', 'stroke');
Copy link
Collaborator

Choose a reason for hiding this comment

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

As long as this is scoped to options.editable === true, can't we still allow clicking on the fill when it's mostly opaque? >0.5 seems a fine cutoff to me. I feel like that's the behavior people will expect - most importantly when there's no stroke but even when there is as long as there's a strong fill.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Revised in 078c007.

}
}

path.style('pointer-events',
!couldHaveActiveShape(gd) || (
lineWidth < 2 || ( // not has a remarkable border
!isOpen && Color.opacity(fillColor) * opacity > 0.5 // not too transparent
)
) ? 'all' : 'stroke'
);
}

path.node().addEventListener('click', function() { return activateShape(gd, path); });
Expand Down
11 changes: 5 additions & 6 deletions src/components/shapes/draw_newshape/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,7 @@ module.exports = {
dflt: 'rgba(0,0,0,0)',
role: 'info',
editType: 'none',
description: [
'Sets the color filling new shapes\' interior.',
'Please note that if using a fillcolor with alpha greater than half,',
'drag inside the active shape starts moving the shape underneath,',
'otherwise a new shape could be started over.'
].join(' ')
description: 'Sets the color filling new shapes\' interior.'
},
fillrule: {
valType: 'enumerated',
Expand Down Expand Up @@ -99,6 +94,10 @@ module.exports = {
},

activeshape: {
description: [
'An \'editable`\' shape can be \'activated\' by clicking on its border line.'
].join(' '),

fillcolor: {
valType: 'color',
dflt: 'rgb(255,0,255)',
Expand Down
130 changes: 125 additions & 5 deletions test/jasmine/tests/draw_newshape_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ describe('Activate and edit editable shapes', function() {
afterEach(destroyGraphDiv);

['mouse'].forEach(function(device) {
it('@flaky reactangle using' + device, function(done) {
it('@flaky reactangle using ' + device, function(done) {
var i = 0; // shape index

Plotly.newPlot(gd, {
Expand Down Expand Up @@ -1224,7 +1224,7 @@ describe('Activate and edit editable shapes', function() {
.then(done);
});

it('@flaky circle using' + device, function(done) {
it('@flaky circle using ' + device, function(done) {
var i = 1; // shape index

Plotly.newPlot(gd, {
Expand Down Expand Up @@ -1281,7 +1281,7 @@ describe('Activate and edit editable shapes', function() {
.then(done);
});

it('@flaky closed-path using' + device, function(done) {
it('@flaky closed-path using ' + device, function(done) {
var i = 2; // shape index

Plotly.newPlot(gd, {
Expand Down Expand Up @@ -1326,7 +1326,7 @@ describe('Activate and edit editable shapes', function() {
.then(done);
});

it('@flaky bezier curves using' + device, function(done) {
it('@flaky bezier curves using ' + device, function(done) {
var i = 5; // shape index

Plotly.newPlot(gd, {
Expand Down Expand Up @@ -1371,7 +1371,7 @@ describe('Activate and edit editable shapes', function() {
.then(done);
});

it('@flaky multi-cell path using' + device, function(done) {
it('@flaky multi-cell path using ' + device, function(done) {
var i = 6; // shape index

Plotly.newPlot(gd, {
Expand Down Expand Up @@ -1426,3 +1426,123 @@ describe('Activate and edit editable shapes', function() {
});
});
});


describe('Activate and edit editable shapes', function() {
var gd;

beforeEach(function() {
gd = createGraphDiv();
});

afterEach(destroyGraphDiv);

it('should not set pointer-events for non-editable shapes i.e. to allow pan/zoom/hover work inside shapes', function(done) {
Plotly.newPlot(gd, {
data: [{
mode: 'markers',
x: [1, 3, 3],
y: [2, 1, 3]
}],
layout: {
shapes: [
{
x0: 1.5,
x1: 2.5,
y0: 1.5,
y1: 2.5,
fillcolor: 'blue'
}
]
}
})

.then(function() {
var el = Plotly.d3.selectAll('.shapelayer path')[0][0];
var pointerEvents = el.style['pointer-events'];
expect(pointerEvents).not.toBe('all');
expect(pointerEvents).not.toBe('stroke');
expect(pointerEvents).toBe('');
})

.catch(failTest)
.then(done);
});

it('should provide invisible border & set pointer-events to "stroke" for editable shapes i.e. to allow shape activation', function(done) {
Plotly.newPlot(gd, {
data: [{
mode: 'markers',
x: [1, 3, 3],
y: [2, 1, 3]
}],
layout: {
shapes: [
{
editable: true,
x0: 1.5,
x1: 2.5,
y0: 1.5,
y1: 2.5,
fillcolor: 'blue',
line: {
width: 0,
dash: 'dash',
color: 'black'
}
}
]
}
})

.then(function() {
var el = Plotly.d3.selectAll('.shapelayer path')[0][0];
expect(el.style['pointer-events']).toBe('stroke');
expect(el.style.stroke).toBe('rgb(0, 0, 0)'); // no color
expect(el.style['stroke-opacity']).toBe('0'); // invisible
expect(el.style['stroke-width']).toBe('5px'); // some pixels to activate shape
})

.catch(failTest)
.then(done);
});

it('should not provide invisible border & set pointer-events to "stroke" for shapes made editable via config', function(done) {
Plotly.newPlot(gd, {
data: [{
mode: 'markers',
x: [1, 3, 3],
y: [2, 1, 3]
}],
layout: {
shapes: [
{
x0: 1.5,
x1: 2.5,
y0: 1.5,
y1: 2.5,
fillcolor: 'blue',
line: {
width: 0,
dash: 'dash',
color: 'black'
}
}
]
}, onfig: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
}, onfig: {
}, config: {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

typo of the week

editable: true
}
})

.then(function() {
var el = Plotly.d3.selectAll('.shapelayer path')[0][0];
expect(el.style['pointer-events']).toBe('');
expect(el.style.stroke).toBe('rgb(0, 0, 0)'); // no color
expect(el.style['stroke-opacity']).toBe('0'); // invisible
expect(el.style['stroke-width']).toBe('0px'); // no extra pixels
})

.catch(failTest)
.then(done);
});
});