Skip to content

Commit

Permalink
Merge pull request #487 from plotly/editable-drag-bugs
Browse files Browse the repository at this point in the history
Legend: fix drag movement when `editable: true`
  • Loading branch information
mdtusz committed Apr 29, 2016
2 parents 23421af + ee0b452 commit c662738
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 30 deletions.
36 changes: 13 additions & 23 deletions src/components/legend/draw.js
Expand Up @@ -13,7 +13,6 @@ var d3 = require('d3');

var Plotly = require('../../plotly');
var Lib = require('../../lib');
var setCursor = require('../../lib/setcursor');
var Plots = require('../../plots/plots');
var dragElement = require('../dragelement');
var Drawing = require('../drawing');
Expand Down Expand Up @@ -326,38 +325,29 @@ module.exports = function draw(gd) {
}

if(gd._context.editable) {
var xf,
yf,
x0,
y0,
lw,
lh;
var xf, yf, x0, y0;

legend.classed('cursor-move', true);

dragElement.init({
element: legend.node(),
prepFn: function() {
x0 = Number(legend.attr('x'));
y0 = Number(legend.attr('y'));
lw = Number(legend.attr('width'));
lh = Number(legend.attr('height'));
setCursor(legend);
var transform = Lib.getTranslate(legend);

x0 = transform.x;
y0 = transform.y;
},
moveFn: function(dx, dy) {
var gs = gd._fullLayout._size;

legend.call(Drawing.setPosition, x0+dx, y0+dy);
var newX = x0 + dx,
newY = y0 + dy;

xf = dragElement.align(x0+dx, lw, gs.l, gs.l+gs.w,
opts.xanchor);
yf = dragElement.align(y0+dy+lh, -lh, gs.t+gs.h, gs.t,
opts.yanchor);
var transform = 'translate(' + newX + ', ' + newY + ')';
legend.attr('transform', transform);

var csr = dragElement.getCursor(xf, yf,
opts.xanchor, opts.yanchor);
setCursor(legend, csr);
xf = dragElement.align(newX, 0, gs.l, gs.l+gs.w, opts.xanchor);
yf = dragElement.align(newY, 0, gs.t+gs.h, gs.t, opts.yanchor);
},
doneFn: function(dragged) {
setCursor(legend);
if(dragged && xf !== undefined && yf !== undefined) {
Plotly.relayout(gd, {'legend.x': xf, 'legend.y': yf});
}
Expand Down
36 changes: 36 additions & 0 deletions src/lib/index.js
Expand Up @@ -430,6 +430,42 @@ lib.addStyleRule = function(selector, styleString) {
else console.warn('addStyleRule failed');
};

lib.getTranslate = function(element) {

var re = /(\btranslate\()(\d*\.?\d*)([^\d]*)(\d*\.?\d*)([^\d]*)(.*)/,
getter = element.attr ? 'attr' : 'getAttribute',
transform = element[getter]('transform') || '';

var translate = transform.replace(re, function(match, p1, p2, p3, p4) {
return [p2, p4].join(' ');
})
.split(' ');

return {
x: +translate[0] || 0,
y: +translate[1] || 0
};
};

lib.setTranslate = function(element, x, y) {

var re = /(\btranslate\(.*?\);?)/,
getter = element.attr ? 'attr' : 'getAttribute',
setter = element.attr ? 'attr' : 'setAttribute',
transform = element[getter]('transform') || '';

x = x || 0;
y = y || 0;

transform = transform.replace(re, '').trim();
transform += ' translate(' + x + ', ' + y + ')';
transform = transform.trim();

element[setter]('transform', transform);

return transform;
};

lib.isIE = function() {
return typeof window.navigator.msSaveBlob !== 'undefined';
};
87 changes: 80 additions & 7 deletions test/jasmine/tests/config_test.js
@@ -1,19 +1,20 @@
var Plotly = require('@lib/index');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');

describe('config argument', function() {

var gd;
describe('showLink attribute', function() {

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

afterEach(destroyGraphDiv);
beforeEach(function(done) {
gd = createGraphDiv();
done();
});

describe('showLink attribute', function() {
afterEach(destroyGraphDiv);

it('should not display the edit link by default', function() {
Plotly.plot(gd, [], {});
Expand All @@ -39,4 +40,76 @@ describe('config argument', function() {
expect(bBox.height).toBeGreaterThan(0);
});
});


describe('editable attribute', function() {

var gd;

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

Plotly.plot(gd, [
{ x: [1,2,3], y: [1,2,3] },
{ x: [1,2,3], y: [3,2,1] }
], {
width: 600,
height: 400
}, { editable: true })
.then(done);
});

afterEach(destroyGraphDiv);

function checkIfEditable(elClass, text) {
var label = document.getElementsByClassName(elClass)[0];

expect(label.textContent).toBe(text);

var labelBox = label.getBoundingClientRect(),
labelX = labelBox.left + labelBox.width / 2,
labelY = labelBox.top + labelBox.height / 2;

mouseEvent('click', labelX, labelY);

var editBox = document.getElementsByClassName('plugin-editable editable')[0];
expect(editBox).toBeDefined();
expect(editBox.textContent).toBe(text);
expect(editBox.getAttribute('contenteditable')).toBe('true');
}

it('should make titles editable', function() {
checkIfEditable('gtitle', 'Click to enter Plot title');
});

it('should make x axes labels editable', function() {
checkIfEditable('g-xtitle', 'Click to enter X axis title');
});

it('should make y axes labels editable', function() {
checkIfEditable('g-ytitle', 'Click to enter Y axis title');
});

it('should make legend labels editable', function() {
checkIfEditable('legendtext', 'trace 0');
});

it('should make legends draggable', function() {

var legend = document.getElementsByClassName('legend')[0],
legendBox = legend.getBoundingClientRect(),
legendX = legendBox.left + legendBox.width / 2,
legendY = legendBox.top + legendBox.height / 2;

mouseEvent('mousedown', legendX, legendY);
mouseEvent('mousemove', legendX - 20, legendY + 20);
mouseEvent('mouseup', legendX - 20, legendY + 20);

var movedlegendBox = legend.getBoundingClientRect();

expect(movedlegendBox.left).not.toBe(legendBox.left);
expect(movedlegendBox.top).not.toBe(legendBox.top);

});
});
});
87 changes: 87 additions & 0 deletions test/jasmine/tests/lib_test.js
Expand Up @@ -770,4 +770,91 @@ describe('Test lib.js:', function() {
});
});

describe('getTranslate', function() {

it('should work with regular DOM elements', function() {
var el = document.createElement('div');

expect(Lib.getTranslate(el)).toEqual({ x: 0, y: 0 });

el.setAttribute('transform', 'translate(123.45px, 67)');
expect(Lib.getTranslate(el)).toEqual({ x: 123.45, y: 67 });

el.setAttribute('transform', 'translate(123.45)');
expect(Lib.getTranslate(el)).toEqual({ x: 123.45, y: 0 });

el.setAttribute('transform', 'translate(1 2)');
expect(Lib.getTranslate(el)).toEqual({ x: 1, y: 2 });

el.setAttribute('transform', 'translate(1 2); rotate(20deg)');
expect(Lib.getTranslate(el)).toEqual({ x: 1, y: 2 });

el.setAttribute('transform', 'rotate(20deg)');
expect(Lib.getTranslate(el)).toEqual({ x: 0, y: 0 });
});

it('should work with d3 elements', function() {
var el = d3.select(document.createElement('div'));

el.attr('transform', 'translate(123.45px, 67)');
expect(Lib.getTranslate(el)).toEqual({ x: 123.45, y: 67 });

el.attr('transform', 'translate(123.45)');
expect(Lib.getTranslate(el)).toEqual({ x: 123.45, y: 0 });

el.attr('transform', 'translate(1 2)');
expect(Lib.getTranslate(el)).toEqual({ x: 1, y: 2 });

el.attr('transform', 'translate(1 2); rotate(20)');
expect(Lib.getTranslate(el)).toEqual({ x: 1, y: 2 });

el.attr('transform', 'rotate(20)');
expect(Lib.getTranslate(el)).toEqual({ x: 0, y: 0 });
});

});

describe('setTranslate', function() {

it('should work with regular DOM elements', function() {
var el = document.createElement('div');

Lib.setTranslate(el, 5);
expect(el.getAttribute('transform')).toBe('translate(5, 0)');

Lib.setTranslate(el, 10, 20);
expect(el.getAttribute('transform')).toBe('translate(10, 20)');

Lib.setTranslate(el, 30, 40);
expect(el.getAttribute('transform')).toBe('translate(30, 40)');

Lib.setTranslate(el);
expect(el.getAttribute('transform')).toBe('translate(0, 0)');

el.setAttribute('transform', 'translate(0, 0); rotate(30)');
Lib.setTranslate(el, 30, 40);
expect(el.getAttribute('transform')).toBe('rotate(30) translate(30, 40)');
});

it('should work with d3 elements', function() {
var el = d3.select(document.createElement('div'));

Lib.setTranslate(el, 5);
expect(el.attr('transform')).toBe('translate(5, 0)');

Lib.setTranslate(el, 10, 20);
expect(el.attr('transform')).toBe('translate(10, 20)');

Lib.setTranslate(el, 30, 40);
expect(el.attr('transform')).toBe('translate(30, 40)');

Lib.setTranslate(el);
expect(el.attr('transform')).toBe('translate(0, 0)');

el.attr('transform', 'translate(0, 0); rotate(30)');
Lib.setTranslate(el, 30, 40);
expect(el.attr('transform')).toBe('rotate(30) translate(30, 40)');
});
});

});

0 comments on commit c662738

Please sign in to comment.