Skip to content

Instantly share code, notes, and snippets.

@justinlevi
Created October 26, 2017 18:53
Show Gist options
  • Save justinlevi/fa6afbe108620c9806c39b325c17bdef to your computer and use it in GitHub Desktop.
Save justinlevi/fa6afbe108620c9806c39b325c17bdef to your computer and use it in GitHub Desktop.
wavesjs/waves-ui : Custom Segment Behavior - Shopping/Trolly metaphor
import * as ui from 'waves-ui';
class CollisionSegmentBehavior extends ui.behaviors.BaseBehavior {
segmentsData = [];
DIRECTION = {
LEFT: 'LEFT',
RIGHT: 'RIGHT'
};
segmentIndex = (search) => {return this.segmentsData.findIndex( obj => { return obj === search }); };
segmentValues = (renderingContext, shape, dataObj) => {
return ({
startX: renderingContext.timeToPixel(shape.x(dataObj)),
// y: renderingContext.valueToPixel(shape.y(dataObj)),
endX: renderingContext.timeToPixel(shape.x(dataObj) + shape.width(dataObj)),
// height: renderingContext.valueToPixel(shape.height(dataObj))
});
};
constructor(segmentsData) {
super();
// segmentsData is a reference to the data defining all your segments
this.segmentsData = segmentsData;
// binding
this.isTouchingSibling = this.isTouchingSibling.bind(this);
this.connectedSiblings = this.connectedSiblings.bind(this);
}
edit(renderingContext, shape, datum, dx, dy, target) {
const classList = target.classList;
let action = 'move';
if (classList.contains('handler') && classList.contains('left')) {
action = 'resizeLeft';
} else if (classList.contains('handler') && classList.contains('right')) {
action = 'resizeRight';
}
this[`_${action}`](renderingContext, shape, datum, dx, dy, target);
}
isTouchingSibling(renderingContext, shape, currentSegmentObj, nextSegmentObj, direction) {
if (!nextSegmentObj) { return }
// CONVENIENCE
const { segmentValues, DIRECTION } = this;
const { LEFT, RIGHT} = DIRECTION;
const currentSegmentValues = segmentValues(renderingContext, shape, currentSegmentObj);
const cSegStart = currentSegmentValues.startX;
const cSegEnd = currentSegmentValues.endX;
const nextSegmentValues = segmentValues(renderingContext, shape, nextSegmentObj);
const nSegStart = nextSegmentValues.startX;
const nSegEnd = nextSegmentValues.endX;
if (direction === LEFT) {
// Does the left edge of the current segment hit the right edge of the next segment
return (cSegStart <= nSegEnd) ? true : false;
}else if (direction === RIGHT) {
// Does the right edge of the current segment hit the left edge of the next segment
return (cSegEnd >= nSegStart) ? true : false;
}
return false;
}
connectedSiblings(renderingContext, shape, currentIndex, direction, siblings = []) {
// CONVENIENCE
const { DIRECTION, segmentsData, isTouchingSibling, connectedSiblings } = this;
const { LEFT, RIGHT } = DIRECTION;
const currentSegmentObj = this.segmentsData[currentIndex];
// Exception cases : FIRST & LAST segments
if (currentIndex === 0 && direction === LEFT ) { return [currentSegmentObj] }
if (currentIndex === segmentsData.length - 1 && direction === RIGHT ) { return [currentSegmentObj] }
const siblingIndex = (direction === LEFT) ? currentIndex - 1 : currentIndex + 1;
const sibling = segmentsData[siblingIndex];
// recursion :(
if ( siblingIndex >= 0 && siblingIndex < segmentsData.length){
connectedSiblings(renderingContext, shape, siblingIndex, direction, siblings)
}
const isTouching = isTouchingSibling(renderingContext, shape, currentSegmentObj, sibling, direction);
if ( isTouching === true ){
siblings.push(sibling);
// TO DO: TRY SELECTING NEIGHBOR
// Do all selected neighbors receive the edit callback when an event is triggered?
}
return siblings;
}
_move(renderingContext, shape, dataObj, dx, dy, target) {
// convenience destructuring
const { segmentIndex, DIRECTION, connectedSiblings } = this;
const { LEFT, RIGHT } = DIRECTION;
// Build Collision Train Array
const currentIndex = segmentIndex(dataObj);
const direction = (dx < 0) ? LEFT : RIGHT;
const train = connectedSiblings(renderingContext, shape, currentIndex, direction);
if (train.length === 0){
train.push(dataObj);
}
// TODO: loop through and make sure siblings are set end to end
train.forEach(sibling => {
const x = renderingContext.timeToPixel(shape.x(sibling))
const targetX = Math.max(x + dx, 0);
shape.x(sibling, renderingContext.timeToPixel.invert(targetX));
});
}
_resizeLeft(renderingContext, shape, datum, dx, dy, target) {
// current values
const x = renderingContext.timeToPixel(shape.x(datum));
const width = renderingContext.timeToPixel(shape.width(datum));
// target values
let maxTargetX = x + width;
let targetX = x + dx < maxTargetX ? Math.max(x + dx, 0) : x;
let targetWidth = targetX !== 0 ? Math.max(width - dx, 1) : width;
shape.x(datum, renderingContext.timeToPixel.invert(targetX));
shape.width(datum, renderingContext.timeToPixel.invert(targetWidth));
}
_resizeRight(renderingContext, shape, datum, dx, dy, target) {
// current values
const width = renderingContext.timeToPixel(shape.width(datum));
// target values
let targetWidth = Math.max(width + dx, 1);
shape.width(datum, renderingContext.timeToPixel.invert(targetWidth));
}
}
export default CollisionSegmentBehavior;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment