@@ -76,7 +76,10 @@ export default function drawDropsTimeline({
7676 console . log ( 'Drawable area:' , drawableAreaWidth , drawableAreaHeight ) ;
7777
7878 const chartGroup = svg . append ( 'g' )
79- . attr ( 'transform' , translate ( margins . left , margins . top ) ) ;
79+ . attr ( 'transform' , translate ( margins . left , margins . top ) )
80+ . attr ( 'class' , 'interaction-chart' )
81+ . attr ( 'data-selected' , 'false' ) ;
82+ const chartGroupData = chartGroup . node ( ) ?. dataset ;
8083
8184
8285 //Scales
@@ -238,6 +241,12 @@ export default function drawDropsTimeline({
238241 . attr ( 'stroke-width' , 1 )
239242 . attr ( 'stroke-dasharray' , '3,3' ) ;
240243
244+ const cursorHighlight = chartGroup . append ( 'rect' )
245+ . attr ( 'fill' , 'transparent' )
246+ . attr ( 'height' , drawableAreaHeight )
247+ . attr ( 'opacity' , '0' )
248+ . attr ( 'class' , 'transition-opacity interaction-highlight' ) ;
249+
241250 //Range selector mark
242251 const defs = chartGroup . append ( 'defs' ) ;
243252 const mask = defs . append ( 'mask' )
@@ -258,6 +267,14 @@ export default function drawDropsTimeline({
258267 . attr ( 'mask' , `url(#${ maskElmntId } )` ) ;
259268
260269 //Helpers
270+ const getRangeBar = ( x1 : number , x2 : number ) => {
271+ const x1Floor = Math . floor ( x1 ) ;
272+ const x2Floor = Math . floor ( x2 ) ;
273+ const start = Math . min ( x1Floor , x2Floor ) + 0.5 - barCenterOffset ;
274+ const width = Math . abs ( x2Floor - x1Floor ) + intervalWidth + 0.5 ;
275+ return { start, width } ;
276+ }
277+
261278 const updateRangeRect = ( x1 ?: number , x2 ?: number ) => {
262279 //Hide mask
263280 if (
@@ -266,16 +283,15 @@ export default function drawDropsTimeline({
266283 || ( x1 > drawableAreaWidth && x2 > drawableAreaWidth )
267284 ) {
268285 maskArea . attr ( 'opacity' , '0' ) ;
286+ chartGroup . attr ( 'data-selected' , 'false' ) ;
269287 return ;
270288 }
271289
272290 //Set mask
273- const x1Floor = Math . floor ( x1 ) ;
274- const x2Floor = Math . floor ( x2 ) ;
275- maskRect
276- . attr ( 'x' , Math . min ( x1Floor , x2Floor ) + 0.5 - barCenterOffset )
277- . attr ( 'width' , Math . abs ( x2Floor - x1Floor ) + intervalWidth + 0.5 ) ;
291+ const { start, width } = getRangeBar ( x1 , x2 ) ;
292+ maskRect . attr ( 'x' , start ) . attr ( 'width' , width ) ;
278293 maskArea . attr ( 'opacity' , '1' ) ;
294+ chartGroup . attr ( 'data-selected' , 'true' ) ;
279295 }
280296 const setUpstreamRangeState = ( range : [ date1 : Date , date2 : Date ] | null ) => {
281297 if ( ! Array . isArray ( range ) || range . length !== 2 ) {
@@ -320,13 +336,14 @@ export default function drawDropsTimeline({
320336 }
321337
322338 //Find the closest data point for a given X value
339+ const filteredLog = data . log . filter ( ( datum ) => datum . drops . length > 0 ) ;
323340 const timeBisector = d3 . bisector ( ( interval : TimelineDropsDatum ) => interval . startDate ) . center ;
324341 const findClosestDatum = ( pointerX : number ) => {
325342 // const xPosDate = timeScale.invert(pointerX - intervalWidth / 2);
326343 const xPosDate = timeScale . invert ( pointerX ) ;
327- const indexFound = timeBisector ( data . log , xPosDate ) ;
344+ const indexFound = timeBisector ( filteredLog , xPosDate ) ;
328345 if ( indexFound === - 1 ) return ;
329- const datum = data . log [ indexFound ] ;
346+ const datum = filteredLog [ indexFound ] ;
330347 const datumStartTs = datum . startDate . getTime ( ) ;
331348 return {
332349 datum,
@@ -341,7 +358,10 @@ export default function drawDropsTimeline({
341358 const handleMouseMove = ( pointerX : number ) => {
342359 // Find closest data point
343360 const datumFound = findClosestDatum ( pointerX ) ;
344- if ( ! datumFound ) return ;
361+ if ( ! datumFound ) {
362+ cursorHighlight . attr ( 'opacity' , '0' ) ;
363+ return ;
364+ }
345365 const { datum, datumStartX, dataumIndex } = datumFound ;
346366 if ( dataumIndex === lastDatumIndex ) return ;
347367 lastDatumIndex = dataumIndex ;
@@ -352,6 +372,8 @@ export default function drawDropsTimeline({
352372 return updateRangeRect ( rangeStartData . x , datumStartX ) ;
353373 }
354374
375+ if ( chartGroupData ?. selected === 'true' ) return ;
376+
355377 //Set legend data
356378 const allNumEls = legendRef . querySelectorAll < HTMLSpanElement > ( 'span[data-category]' ) ;
357379 for ( const numEl of allNumEls ) {
@@ -389,13 +411,21 @@ export default function drawDropsTimeline({
389411 }
390412
391413 // Draw cursor
392- const cursorX = Math . round ( datumStartX + intervalWidth / 2 ) + 0.5 - barCenterOffset ;
393- cursorLineVert . attr ( 'x1' , cursorX ) . attr ( 'y1' , 0 ) . attr ( 'x2' , cursorX ) . attr ( 'y2' , drawableAreaHeight ) ;
414+ // const cursorX = Math.round(datumStartX + intervalWidth / 2) + 0.5 - barCenterOffset;
415+ // cursorLineVert.attr('x1', cursorX).attr('y1', 0).attr('x2', cursorX).attr('y2', drawableAreaHeight);
416+
417+ // Draw cursor highlight bar
418+ const barX = getRangeBar ( datumStartX , datumStartX ) ;
419+ cursorHighlight
420+ . attr ( 'x' , barX . start )
421+ . attr ( 'width' , barX . width )
422+ . attr ( 'opacity' , '1' ) ;
394423 } ;
395424
396425 const handleMouseDown = ( pointerX : number ) => {
397426 const datumFound = findClosestDatum ( pointerX ) ;
398427 if ( ! datumFound ) return ;
428+ chartGroup . attr ( 'data-mousedown' , 'true' ) ;
399429 hideCursor ( ) ;
400430 rangeStartData = {
401431 x : datumFound . datumStartX ,
@@ -405,10 +435,15 @@ export default function drawDropsTimeline({
405435 }
406436
407437 const handleMouseUp = ( pointerX : number ) => {
438+ chartGroup . attr ( 'data-mousedown' , 'false' ) ;
408439 if ( ! rangeStartData ) return clearRangeData ( true ) ;
409440 const datumFound = findClosestDatum ( pointerX ) ;
410441 if ( ! datumFound ) return clearRangeData ( true ) ;
411- if ( ! rangeCrossedThreshold && rangeStartData . datum . startDate . getTime ( ) === datumFound . datum . startDate . getTime ( ) ) {
442+ // if (!rangeCrossedThreshold && rangeStartData.datum.startDate.getTime() === datumFound.datum.startDate.getTime()) {
443+ // return clearRangeData(true);
444+ // }
445+
446+ if ( rangeSelected && chartGroupData ?. selected !== 'true' ) {
412447 return clearRangeData ( true ) ;
413448 }
414449
@@ -423,6 +458,8 @@ export default function drawDropsTimeline({
423458 }
424459
425460 const handleMouseLeave = ( ) => {
461+ chartGroup . attr ( 'data-mousedown' , 'false' ) ;
462+ cursorHighlight . attr ( 'opacity' , '0' ) ;
426463 setTimeout ( ( ) => {
427464 clearRangeData ( ! ! rangeStartData ) ;
428465 hideCursor ( ) ;
@@ -432,30 +469,28 @@ export default function drawDropsTimeline({
432469 // Handle svg mouse events
433470 let isEventInCooldown = false ;
434471 const cooldownTime = 20 ;
435- chartGroup . append ( 'rect' )
436- . attr ( 'width' , drawableAreaWidth )
437- . attr ( 'height' , drawableAreaHeight )
438- . attr ( 'fill' , 'transparent' )
439- . on ( 'mousemove' , function ( event ) {
440- const [ pointerX ] = d3 . pointer ( event ) ;
441- if ( ! isEventInCooldown ) {
442- isEventInCooldown = true ;
472+ chartGroup . on ( 'mousemove' , function ( event ) {
473+ const [ pointerX ] = d3 . pointer ( event ) ;
474+ if ( ! isEventInCooldown ) {
475+ isEventInCooldown = true ;
476+ handleMouseMove ( pointerX ) ;
477+ setTimeout ( ( ) => {
478+ isEventInCooldown = false ;
479+ } , cooldownTime ) ;
480+ } else {
481+ clearTimeout ( cursorRedrawTimeout ) ;
482+ cursorRedrawTimeout = setTimeout ( ( ) => {
443483 handleMouseMove ( pointerX ) ;
444- setTimeout ( ( ) => {
445- isEventInCooldown = false ;
446- } , cooldownTime ) ;
447- } else {
448- clearTimeout ( cursorRedrawTimeout ) ;
449- cursorRedrawTimeout = setTimeout ( ( ) => {
450- handleMouseMove ( pointerX ) ;
451- } , cooldownTime ) ;
452- }
453- } )
454- . on ( 'mousedown' , function ( event ) {
484+ } , cooldownTime ) ;
485+ }
486+ } )
487+ . on ( 'mousedown' , function ( event : MouseEvent ) {
488+ if ( event . button !== 0 ) return ; //left btn only
455489 const [ pointerX ] = d3 . pointer ( event ) ;
456490 handleMouseDown ( pointerX ) ;
457491 } )
458492 . on ( 'mouseup' , function ( event ) {
493+ if ( event . button !== 0 ) return ; //left btn only
459494 const [ pointerX ] = d3 . pointer ( event ) ;
460495 handleMouseUp ( pointerX ) ;
461496 } ) ;
0 commit comments