Skip to content

Commit

Permalink
Merge pull request #743 from poptip/dragevents
Browse files Browse the repository at this point in the history
DragInteraction callbacks for dragstart, drag, and dragend
  • Loading branch information
jtlan committed Aug 19, 2014
2 parents 00da7ce + 1860738 commit ade81f3
Show file tree
Hide file tree
Showing 10 changed files with 6,184 additions and 1,124 deletions.
2,301 changes: 1,974 additions & 327 deletions plottable.d.ts

Large diffs are not rendered by default.

3,300 changes: 2,766 additions & 534 deletions plottable.js

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions src/core/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,6 @@ module Plottable {
wantsHeight: boolean;
}

export interface IPixelArea {
xMin: number;
xMax: number;
yMin: number;
yMax: number;
}

export interface IExtent {
min: number;
max: number;
Expand Down
3 changes: 0 additions & 3 deletions src/interactions/drag/dragBoxInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ export module Interaction {

public _dragstart() {
super._dragstart();
if (this.callbackToCall != null) {
this.callbackToCall(null);
}
this.clearBox();
}

Expand Down
110 changes: 92 additions & 18 deletions src/interactions/drag/dragInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ export module Interaction {
private dragBehavior: D3.Behavior.Drag;
public origin = [0,0];
public location = [0,0];
private constrainX: (n: number) => number;
private constrainY: (n: number) => number;
public callbackToCall: (dragInfo: any) => any;
private constrainX: (n: number) => number;
private constrainY: (n: number) => number;
private ondragstart: (startLocation: Point) => void;
private ondrag: (startLocation: Point, endLocation: Point) => void;
private ondragend: (startLocation: Point, endLocation: Point) => void;

/**
* Creates a Drag.
Expand All @@ -25,14 +27,69 @@ export module Interaction {
}

/**
* Adds a callback to be called when the AreaInteraction triggers.
* Gets the callback that is called when dragging starts.
*
* @param {(a: SelectionArea) => any} cb The function to be called. Takes in a SelectionArea in pixels.
* @returns {AreaInteraction} The calling AreaInteraction.
* @returns {(startLocation: Point) => void}
*/
public callback(cb?: (a: any) => any) {
this.callbackToCall = cb;
return this;
public dragstart(): (startLocation: Point) => void;
/**
* Sets the callback to be called when dragging starts.
*
* @param {(startLocation: Point) => any} cb The function to be called.
* @returns {Drag}
*/
public dragstart(cb: (startLocation: Point) => any): Drag;
public dragstart(cb?: (startLocation: Point) => any): any {
if (cb === undefined) {
return this.ondragstart;
} else {
this.ondragstart = cb;
return this;
}
}

/**
* Gets the callback that is called during dragging.
*
* @returns {(startLocation: Point, endLocation: Point) => void}
*/
public drag(): (startLocation: Point, endLocation: Point) => void;
/**
* Adds a callback to be called during dragging.
*
* @param {(startLocation: Point, endLocation: Point) => any} cb The function to be called.
* @returns {Drag}
*/
public drag(cb: (startLocation: Point, endLocation: Point) => any): Drag;
public drag(cb?: (startLocation: Point, endLocation: Point) => any): any {
if (cb === undefined) {
return this.ondrag;
} else {
this.ondrag = cb;
return this;
}
}

/**
* Gets the callback that is called when dragging ends.
*
* @returns {(startLocation: Point, endLocation: Point) => void}
*/
public dragend(): (startLocation: Point, endLocation: Point) => void;
/**
* Adds a callback to be called when the dragging ends.
*
* @param {(startLocation: Point, endLocation: Point) => any} cb The function to be called. Takes in a SelectionArea in pixels.
* @returns {Drag} The calling Drag.
*/
public dragend(cb: (startLocation: Point, endLocation: Point) => any): Drag;
public dragend(cb?: (startLocation: Point, endLocation: Point) => any): any {
if (cb === undefined) {
return this.ondragend;
} else {
this.ondragend = cb;
return this;
}
}

public _dragstart(){
Expand All @@ -44,13 +101,29 @@ export module Interaction {
this.constrainY = constraintFunction(0, availableHeight);
}

public _doDragstart() {
if (this.ondragstart != null) {
this.ondragstart({x: this.origin[0], y: this.origin[1]});
}
}

public _drag(){
if (!this.dragInitialized) {
this.origin = [d3.event.x, d3.event.y];
this.dragInitialized = true;
this._doDragstart();
}

this.location = [this.constrainX(d3.event.x), this.constrainY(d3.event.y)];
this._doDrag();
}

public _doDrag() {
if (this.ondrag != null) {
var startLocation = {x: this.origin[0], y: this.origin[1]};
var endLocation = {x: this.location[0], y: this.location[1]};
this.ondrag(startLocation, endLocation);
}
}

public _dragend(){
Expand All @@ -62,10 +135,10 @@ export module Interaction {
}

public _doDragend() {
// seperated out so it can be over-ridden by dragInteractions that want to pass out diff information
// eg just x values for an xSelectionInteraction
if (this.callbackToCall != null) {
this.callbackToCall([this.origin, this.location]);
if (this.ondragend != null) {
var startLocation = {x: this.origin[0], y: this.origin[1]};
var endLocation = {x: this.location[0], y: this.location[1]};
this.ondragend(startLocation, endLocation);
}
}

Expand All @@ -79,8 +152,8 @@ export module Interaction {
var xDomainOriginal = xScale != null ? xScale.domain() : null;
var yDomainOriginal = yScale != null ? yScale.domain() : null;
var resetOnNextClick = false;
function callback(pixelArea: IPixelArea) {
if (pixelArea == null) {
function callback(upperLeft: Point, lowerRight: Point) {
if (upperLeft == null || lowerRight == null) {
if (resetOnNextClick) {
if (xScale != null) {
xScale.domain(xDomainOriginal);
Expand All @@ -94,15 +167,16 @@ export module Interaction {
}
resetOnNextClick = false;
if (xScale != null) {
xScale.domain([xScale.invert(pixelArea.xMin), xScale.invert(pixelArea.xMax)]);
xScale.domain([xScale.invert(upperLeft.x), xScale.invert(lowerRight.x)]);
}
if (yScale != null) {
yScale.domain([yScale.invert(pixelArea.yMax), yScale.invert(pixelArea.yMin)]);
yScale.domain([yScale.invert(lowerRight.y), yScale.invert(upperLeft.y)]);
}
this.clearBox();
return;
}
this.callback(callback);
this.drag(callback);
this.dragend(callback);
return this;
}
}
Expand Down
10 changes: 0 additions & 10 deletions src/interactions/drag/xDragBoxInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,6 @@ export module Interaction {
this.setBox(this.origin[0], this.location[0]);
}

public _doDragend(){
if (this.callbackToCall == null) {
return;
}
var xMin = Math.min(this.origin[0], this.location[0]);
var xMax = Math.max(this.origin[0], this.location[0]);
var pixelArea = {xMin: xMin, xMax: xMax};
this.callbackToCall(pixelArea);
}

public setBox(x0: number, x1: number) {
super.setBox(x0, x1, 0, this.componentToListenTo.availableHeight);
return this;
Expand Down
12 changes: 0 additions & 12 deletions src/interactions/drag/xyDragBoxInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,6 @@ export module Interaction {
super._drag();
this.setBox(this.origin[0], this.location[0], this.origin[1], this.location[1]);
}

public _doDragend(){
if (this.callbackToCall == null) {
return;
}
var xMin = Math.min(this.origin[0], this.location[0]);
var xMax = Math.max(this.origin[0], this.location[0]);
var yMin = Math.min(this.origin[1], this.location[1]);
var yMax = Math.max(this.origin[1], this.location[1]);
var pixelArea = {xMin: xMin, xMax: xMax, yMin: yMin, yMax: yMax};
this.callbackToCall(pixelArea);
}
}
}
}
10 changes: 0 additions & 10 deletions src/interactions/drag/yDragBoxInteraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,6 @@ export module Interaction {
this.setBox(this.origin[1], this.location[1]);
}

public _doDragend(){
if (this.callbackToCall == null) {
return;
}
var yMin = Math.min(this.origin[1], this.location[1]);
var yMax = Math.max(this.origin[1], this.location[1]);
var pixelArea = {yMin: yMin, yMax: yMax};
this.callbackToCall(pixelArea);
}

public setBox(y0: number, y1: number) {
super.setBox(0, this.componentToListenTo.availableWidth, y0, y1);
return this;
Expand Down
74 changes: 37 additions & 37 deletions test/interactions/interactionTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,35 +105,37 @@ describe("Interactions", () => {
});

afterEach(() => {
interaction.callback();
interaction.dragstart(null);
interaction.drag(null);
interaction.dragend(null);
interaction.clearBox();
});

it("All callbacks are notified with appropriate data when a drag finishes", () => {
it("All callbacks are notified with appropriate data on drag", () => {
var timesCalled = 0;
var areaCallback = (a: Plottable.SelectionArea) => {
interaction.dragstart(function(a: Plottable.Point) {
timesCalled++;
if (timesCalled === 1) {
assert.deepEqual(a, null, "areaCallback called with null arg on dragstart");
}
if (timesCalled === 2) {
var expectedPixelArea = {
xMin: dragstartX,
xMax: dragendX,
yMin: dragstartY,
yMax: dragendY
};
assert.deepEqual(a, expectedPixelArea, "areaCallback was passed the correct pixel area");
}
};


interaction.callback(areaCallback);
var expectedStartLocation = { x: dragstartX, y: dragstartY };
assert.deepEqual(a, expectedStartLocation, "areaCallback called with null arg on dragstart");
});
interaction.dragend(function(a: Plottable.Point, b: Plottable.Point) {
timesCalled++;
var expectedStart = {
x: dragstartX,
y: dragstartY,
};
var expectedEnd = {
x: dragendX,
y: dragendY
};
assert.deepEqual(a, expectedStart, "areaCallback was passed the correct starting point");
assert.deepEqual(b, expectedEnd, "areaCallback was passed the correct ending point");
});

// fake a drag event
fakeDragSequence((<any> interaction), dragstartX, dragstartY, dragendX, dragendY);

assert.equal(timesCalled, 2, "areaCallback was called twice");
assert.equal(timesCalled, 2, "drag callbacks are called twice");
});

it("Highlights and un-highlights areas appropriately", () => {
Expand Down Expand Up @@ -184,33 +186,31 @@ describe("Interactions", () => {
});

afterEach(() => {
interaction.callback();
interaction.dragstart(null);
interaction.drag(null);
interaction.dragend(null);
interaction.clearBox();
});

it("All callbacks are notified with appropriate data when a drag finishes", () => {
var timesCalled = 0;
var areaCallback = (a: Plottable.SelectionArea) => {
interaction.dragstart(function(a: Plottable.Point) {
timesCalled++;
if (timesCalled === 1) {
assert.deepEqual(a, null, "areaCallback called with null arg on dragstart");
}
if (timesCalled === 2) {
var expectedPixelArea = {
yMin: dragstartY,
yMax: dragendY
};
assert.deepEqual(a, expectedPixelArea, "areaCallback was passed the correct pixel area");
}
};


interaction.callback(areaCallback);
var expectedY = dragstartY;
assert.deepEqual(a.y, expectedY, "areaCallback called with null arg on dragstart");
})
interaction.dragend(function(a: Plottable.Point, b: Plottable.Point) {
timesCalled++;
var expectedStartY = dragstartY;
var expectedEndY = dragendY;
assert.deepEqual(a.y, expectedStartY);
assert.deepEqual(b.y, expectedEndY);
});

// fake a drag event
fakeDragSequence((<any> interaction), dragstartX, dragstartY, dragendX, dragendY);

assert.equal(timesCalled, 2, "areaCallback was called twice");
assert.equal(timesCalled, 2, "drag callbacks area called twice");
});

it("Highlights and un-highlights areas appropriately", () => {
Expand Down
Loading

0 comments on commit ade81f3

Please sign in to comment.