Created
October 26, 2017 18:53
-
-
Save justinlevi/fa6afbe108620c9806c39b325c17bdef to your computer and use it in GitHub Desktop.
wavesjs/waves-ui : Custom Segment Behavior - Shopping/Trolly metaphor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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