@decidables/discountable-elements 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/lib/discountableElements.esm.js +330 -234
- package/lib/discountableElements.esm.js.map +1 -1
- package/lib/discountableElements.esm.min.js +82 -61
- package/lib/discountableElements.esm.min.js.map +1 -1
- package/lib/discountableElements.umd.js +330 -234
- package/lib/discountableElements.umd.js.map +1 -1
- package/lib/discountableElements.umd.min.js +82 -61
- package/lib/discountableElements.umd.min.js.map +1 -1
- package/package.json +4 -4
- package/src/colors.yml +2 -2
- package/src/components/htd-curves.js +445 -338
|
@@ -249,54 +249,91 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
249
249
|
/* shape-rendering: crispEdges; */
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
.
|
|
253
|
-
fill: none;
|
|
254
|
-
stroke: var(---color-element-emphasis);
|
|
255
|
-
stroke-width: 2;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
.curve.interactive {
|
|
259
|
-
cursor: nwse-resize;
|
|
260
|
-
|
|
252
|
+
.option .interactive {
|
|
261
253
|
filter: url("#shadow-2");
|
|
262
254
|
outline: none;
|
|
263
255
|
}
|
|
264
256
|
|
|
265
|
-
.
|
|
257
|
+
.option .interactive:hover {
|
|
266
258
|
filter: url("#shadow-4");
|
|
267
259
|
}
|
|
268
260
|
|
|
269
|
-
.
|
|
261
|
+
.option .interactive:active {
|
|
270
262
|
filter: url("#shadow-8");
|
|
271
263
|
}
|
|
272
264
|
|
|
273
|
-
:host(.keyboard) .
|
|
265
|
+
:host(.keyboard) .option .interactive:focus-within {
|
|
274
266
|
filter: url("#shadow-8");
|
|
275
267
|
}
|
|
276
268
|
|
|
277
|
-
.
|
|
278
|
-
|
|
279
|
-
stroke: var(---color-element-emphasis);
|
|
280
|
-
stroke-width: 2;
|
|
269
|
+
.option .body.interactive:has(~ .point:hover) {
|
|
270
|
+
filter: url("#shadow-4");
|
|
281
271
|
}
|
|
282
272
|
|
|
283
|
-
.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
273
|
+
.option .body.interactive:has(~ .point:active) {
|
|
274
|
+
filter: url("#shadow-8");
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
:host(.keyboard) .option .body.interactive:has(~ .point:focus-within) {
|
|
278
|
+
filter: url("#shadow-8");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.gradient.sooner stop {
|
|
282
|
+
stop-color: var(---color-sooner);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.gradient.later stop {
|
|
286
|
+
stop-color: var(---color-later);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.stop-0,
|
|
290
|
+
.stop-before {
|
|
291
|
+
stop-opacity: 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.stop-after,
|
|
295
|
+
.stop-100 {
|
|
296
|
+
stop-opacity: 1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.fill {
|
|
300
|
+
fill: var(---color-element-enabled);
|
|
301
|
+
fill-opacity: 0.5;
|
|
302
|
+
stroke: none;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.interactive .fill {
|
|
306
|
+
cursor: move;
|
|
307
|
+
|
|
287
308
|
outline: none;
|
|
288
309
|
}
|
|
289
310
|
|
|
290
|
-
.
|
|
291
|
-
|
|
311
|
+
.sooner .fill {
|
|
312
|
+
fill: var(---color-sooner);
|
|
292
313
|
}
|
|
293
314
|
|
|
294
|
-
.
|
|
295
|
-
|
|
315
|
+
.later .fill {
|
|
316
|
+
fill: var(---color-later);
|
|
296
317
|
}
|
|
297
318
|
|
|
298
|
-
|
|
299
|
-
|
|
319
|
+
.trial.sooner .fill {
|
|
320
|
+
fill: url("#sooner-gradient");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.trial.later .fill {
|
|
324
|
+
fill: url("#later-gradient");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.bar {
|
|
328
|
+
fill: none;
|
|
329
|
+
stroke: var(---color-element-emphasis);
|
|
330
|
+
stroke-width: 2;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.interactive .bar {
|
|
334
|
+
cursor: ew-resize;
|
|
335
|
+
|
|
336
|
+
outline: none;
|
|
300
337
|
}
|
|
301
338
|
|
|
302
339
|
.point .mark {
|
|
@@ -314,38 +351,22 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
314
351
|
fill: var(---color-text-inverse);
|
|
315
352
|
}
|
|
316
353
|
|
|
317
|
-
.point.
|
|
354
|
+
.point.interact {
|
|
318
355
|
cursor: ns-resize;
|
|
319
356
|
|
|
320
|
-
filter: url("#shadow-2");
|
|
321
357
|
outline: none;
|
|
322
|
-
|
|
323
|
-
/* HACK: This gets Safari to correctly apply the filter! */
|
|
324
|
-
/* https://github.com/emilbjorklund/svg-weirdness/issues/27 */
|
|
325
|
-
stroke: #000000;
|
|
326
|
-
stroke-opacity: 0;
|
|
327
|
-
stroke-width: 0;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
.point.interactive:hover {
|
|
331
|
-
filter: url("#shadow-4");
|
|
332
|
-
|
|
333
|
-
/* HACK: This gets Safari to correctly apply the filter! */
|
|
334
|
-
stroke: #ff0000;
|
|
335
358
|
}
|
|
336
359
|
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
stroke: #00ff00;
|
|
360
|
+
.curve {
|
|
361
|
+
fill: none;
|
|
362
|
+
stroke: var(---color-element-emphasis);
|
|
363
|
+
stroke-width: 2;
|
|
342
364
|
}
|
|
343
365
|
|
|
344
|
-
|
|
345
|
-
|
|
366
|
+
.curve.interactive {
|
|
367
|
+
cursor: nwse-resize;
|
|
346
368
|
|
|
347
|
-
|
|
348
|
-
stroke: #0000ff;
|
|
369
|
+
outline: none;
|
|
349
370
|
}
|
|
350
371
|
|
|
351
372
|
/* Make larger targets for touch users */
|
|
@@ -434,6 +455,38 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
434
455
|
const svgEnter = svgUpdate.enter().append('svg')
|
|
435
456
|
.classed('main', true);
|
|
436
457
|
svgEnter.html(DiscountableElement.svgDefs);
|
|
458
|
+
// Gradients for fill animations
|
|
459
|
+
const svgDefs = svgEnter.append('defs');
|
|
460
|
+
const soonerGradient = svgDefs.append('linearGradient')
|
|
461
|
+
.classed('gradient sooner', true)
|
|
462
|
+
.attr('id', 'sooner-gradient');
|
|
463
|
+
soonerGradient.append('stop')
|
|
464
|
+
.classed('stop-0', true)
|
|
465
|
+
.attr('offset', '0');
|
|
466
|
+
soonerGradient.append('stop')
|
|
467
|
+
.classed('stop-before animation', true)
|
|
468
|
+
.attr('offset', '1');
|
|
469
|
+
soonerGradient.append('stop')
|
|
470
|
+
.classed('stop-after animation', true)
|
|
471
|
+
.attr('offset', '1');
|
|
472
|
+
soonerGradient.append('stop')
|
|
473
|
+
.classed('stop-100', true)
|
|
474
|
+
.attr('offset', '1');
|
|
475
|
+
const laterGradient = svgDefs.append('linearGradient')
|
|
476
|
+
.classed('gradient later', true)
|
|
477
|
+
.attr('id', 'later-gradient');
|
|
478
|
+
laterGradient.append('stop')
|
|
479
|
+
.classed('stop-0', true)
|
|
480
|
+
.attr('offset', '0');
|
|
481
|
+
laterGradient.append('stop')
|
|
482
|
+
.classed('stop-before animation', true)
|
|
483
|
+
.attr('offset', '1');
|
|
484
|
+
laterGradient.append('stop')
|
|
485
|
+
.classed('stop-after animation', true)
|
|
486
|
+
.attr('offset', '1');
|
|
487
|
+
laterGradient.append('stop')
|
|
488
|
+
.classed('stop-100', true)
|
|
489
|
+
.attr('offset', '1');
|
|
437
490
|
// MERGE
|
|
438
491
|
const svgMerge = svgEnter.merge(svgUpdate)
|
|
439
492
|
.attr('viewBox', `0 0 ${elementWidth} ${elementHeight}`);
|
|
@@ -554,13 +607,27 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
554
607
|
);
|
|
555
608
|
// ENTER
|
|
556
609
|
const optionEnter = optionUpdate.enter().append('g')
|
|
557
|
-
.
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
610
|
+
.attr('class', (datum) => {
|
|
611
|
+
const labelClass = datum.label === 's' ? 'sooner' : datum.label === 'l' ? 'later' : '';
|
|
612
|
+
const trialClass = datum.trial ? 'trial' : '';
|
|
613
|
+
return `option ${labelClass} ${trialClass}`;
|
|
614
|
+
});
|
|
615
|
+
// Body (Fill, Bar, Point)
|
|
616
|
+
const bodyEnter = optionEnter.append('g')
|
|
617
|
+
.classed('body', true);
|
|
618
|
+
// Fill
|
|
619
|
+
const fillEnter = bodyEnter.append('g')
|
|
620
|
+
.classed('fill', true)
|
|
621
|
+
.attr('clip-path', 'url(#clip-htd-curves)')
|
|
622
|
+
.each((datum) => {
|
|
623
|
+
if (datum.trial) {
|
|
624
|
+
svgMerge
|
|
625
|
+
.selectAll('.gradient .animation')
|
|
626
|
+
.attr('offset', 1);
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
fillEnter.append('path')
|
|
630
|
+
.classed('region', true)
|
|
564
631
|
.attr('d', (datum) => {
|
|
565
632
|
const curve = d3.range(xScale(datum.d), xScale(0), -1).map((range) => {
|
|
566
633
|
return {
|
|
@@ -572,8 +639,20 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
572
639
|
),
|
|
573
640
|
};
|
|
574
641
|
});
|
|
575
|
-
return line(curve);
|
|
576
|
-
})
|
|
642
|
+
return line([...curve, {d: 0, v: 0}, {d: datum.d, v: 0}]);
|
|
643
|
+
});
|
|
644
|
+
// Bar
|
|
645
|
+
const barEnter = bodyEnter.append('g')
|
|
646
|
+
.classed('bar', true);
|
|
647
|
+
barEnter.append('line')
|
|
648
|
+
.classed('line', true);
|
|
649
|
+
barEnter.append('line')
|
|
650
|
+
.classed('line touch', true);
|
|
651
|
+
barEnter.selectAll('.line')
|
|
652
|
+
.attr('x1', (datum) => { return xScale(datum.d); })
|
|
653
|
+
.attr('x2', (datum) => { return xScale(datum.d); })
|
|
654
|
+
.attr('y1', yScale(0))
|
|
655
|
+
.attr('y2', (datum) => { return yScale(datum.a); })
|
|
577
656
|
.attr('stroke-dasharray', (datum, index, nodes) => {
|
|
578
657
|
if (datum.trial) {
|
|
579
658
|
const length = nodes[index].getTotalLength();
|
|
@@ -581,8 +660,20 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
581
660
|
}
|
|
582
661
|
return 'none';
|
|
583
662
|
});
|
|
663
|
+
// Point
|
|
664
|
+
const pointEnter = bodyEnter.append('g')
|
|
665
|
+
.classed('point', true);
|
|
666
|
+
pointEnter.append('circle')
|
|
667
|
+
.classed('mark touch', true);
|
|
668
|
+
// Curve
|
|
669
|
+
const curveEnter = optionEnter.append('g')
|
|
670
|
+
.classed('curve', true)
|
|
671
|
+
.attr('clip-path', 'url(#clip-htd-curves)');
|
|
672
|
+
curveEnter.append('path')
|
|
673
|
+
.classed('path', true);
|
|
584
674
|
curveEnter.append('path')
|
|
585
|
-
.classed('path touch', true)
|
|
675
|
+
.classed('path touch', true);
|
|
676
|
+
curveEnter.selectAll('.path')
|
|
586
677
|
.attr('d', (datum) => {
|
|
587
678
|
const curve = d3.range(xScale(datum.d), xScale(0), -1).map((range) => {
|
|
588
679
|
return {
|
|
@@ -603,38 +694,14 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
603
694
|
}
|
|
604
695
|
return 'none';
|
|
605
696
|
});
|
|
606
|
-
//
|
|
607
|
-
const
|
|
608
|
-
.classed('
|
|
609
|
-
|
|
610
|
-
.classed('
|
|
611
|
-
|
|
612
|
-
.
|
|
613
|
-
|
|
614
|
-
.attr('y2', (datum) => { return yScale(datum.a); })
|
|
615
|
-
.attr('stroke-dasharray', (datum, index, nodes) => {
|
|
616
|
-
if (datum.trial) {
|
|
617
|
-
const length = nodes[index].getTotalLength();
|
|
618
|
-
return `0,${length}`;
|
|
619
|
-
}
|
|
620
|
-
return 'none';
|
|
621
|
-
});
|
|
622
|
-
barEnter.append('line')
|
|
623
|
-
.classed('line touch', true)
|
|
624
|
-
.attr('x1', (datum) => { return xScale(datum.d); })
|
|
625
|
-
.attr('x2', (datum) => { return xScale(datum.d); })
|
|
626
|
-
.attr('y1', yScale(0))
|
|
627
|
-
.attr('y2', (datum) => { return yScale(datum.a); })
|
|
628
|
-
.attr('stroke-dasharray', (datum, index, nodes) => {
|
|
629
|
-
if (datum.trial) {
|
|
630
|
-
const length = nodes[index].getTotalLength();
|
|
631
|
-
return `0,${length}`;
|
|
632
|
-
}
|
|
633
|
-
return 'none';
|
|
634
|
-
});
|
|
635
|
-
// Point
|
|
636
|
-
const pointEnter = optionEnter.append('g')
|
|
637
|
-
.classed('point', true)
|
|
697
|
+
// Point (again)
|
|
698
|
+
const topPointEnter = optionEnter.append('g')
|
|
699
|
+
.classed('point top-point', true);
|
|
700
|
+
topPointEnter.append('circle')
|
|
701
|
+
.classed('mark touch', true);
|
|
702
|
+
topPointEnter.append('text')
|
|
703
|
+
.classed('label', true);
|
|
704
|
+
optionEnter.selectAll('.point')
|
|
638
705
|
.attr('transform', (datum) => {
|
|
639
706
|
return `translate(${xScale(datum.d)}, ${yScale(datum.a)})`;
|
|
640
707
|
})
|
|
@@ -644,94 +711,57 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
644
711
|
}
|
|
645
712
|
return 1;
|
|
646
713
|
});
|
|
647
|
-
|
|
648
|
-
.classed('mark touch', true);
|
|
649
|
-
pointEnter.append('text')
|
|
650
|
-
.classed('label', true);
|
|
714
|
+
|
|
651
715
|
// MERGE
|
|
652
716
|
const optionMerge = optionEnter.merge(optionUpdate);
|
|
653
717
|
|
|
654
718
|
// Interactive options
|
|
655
|
-
//
|
|
656
|
-
optionMerge
|
|
719
|
+
// Body (Fill, Bar, Point)
|
|
720
|
+
const bodyMergeInteractive = optionMerge
|
|
657
721
|
.filter((datum, index, nodes) => {
|
|
658
|
-
return (this.interactive && !d3.select(nodes[index]).select('.
|
|
722
|
+
return (this.interactive && !datum.trial && !d3.select(nodes[index]).select('.body').classed('interactive'));
|
|
659
723
|
})
|
|
660
|
-
.select('.
|
|
661
|
-
|
|
724
|
+
.select('.body');
|
|
725
|
+
bodyMergeInteractive.classed('interactive', true)
|
|
662
726
|
.attr('tabindex', 0)
|
|
663
|
-
// Drag interaction
|
|
664
|
-
.call(d3.drag()
|
|
665
|
-
.subject((event) => {
|
|
666
|
-
return {
|
|
667
|
-
x: event.x,
|
|
668
|
-
y: event.y,
|
|
669
|
-
};
|
|
670
|
-
})
|
|
671
|
-
.on('start', (event) => {
|
|
672
|
-
const element = event.currentTarget;
|
|
673
|
-
d3.select(element).classed('dragging', true);
|
|
674
|
-
})
|
|
675
|
-
.on('drag', (event, datum) => {
|
|
676
|
-
this.drag = true;
|
|
677
|
-
const dragD = datum.d - xScale.invert(event.x);
|
|
678
|
-
const d = (dragD < 0)
|
|
679
|
-
? 0
|
|
680
|
-
: (dragD > datum.d)
|
|
681
|
-
? datum.d
|
|
682
|
-
: dragD;
|
|
683
|
-
const dragV = yScale.invert(event.y);
|
|
684
|
-
const v = (dragV <= 0)
|
|
685
|
-
? 0.001
|
|
686
|
-
: (dragV > datum.a)
|
|
687
|
-
? datum.a
|
|
688
|
-
: dragV;
|
|
689
|
-
const k = HTDMath.adv2k(datum.a, d, v);
|
|
690
|
-
this.k = (k < HTDMath.k.MIN)
|
|
691
|
-
? HTDMath.k.MIN
|
|
692
|
-
: (k > HTDMath.k.MAX)
|
|
693
|
-
? HTDMath.k.MAX
|
|
694
|
-
: k;
|
|
695
|
-
this.alignState();
|
|
696
|
-
this.requestUpdate();
|
|
697
|
-
this.dispatchEvent(new CustomEvent('htd-curves-change', {
|
|
698
|
-
detail: {
|
|
699
|
-
name: datum.name,
|
|
700
|
-
a: datum.a,
|
|
701
|
-
d: datum.d,
|
|
702
|
-
k: this.k,
|
|
703
|
-
label: datum.label,
|
|
704
|
-
},
|
|
705
|
-
bubbles: true,
|
|
706
|
-
}));
|
|
707
|
-
})
|
|
708
|
-
.on('end', (event) => {
|
|
709
|
-
const element = event.currentTarget;
|
|
710
|
-
d3.select(element).classed('dragging', false);
|
|
711
|
-
}))
|
|
712
727
|
// Keyboard interaction
|
|
713
728
|
.on('keydown', (event, datum) => {
|
|
714
|
-
if (['ArrowUp', 'ArrowDown', '
|
|
715
|
-
let
|
|
729
|
+
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
|
730
|
+
let keyA = datum.a;
|
|
731
|
+
let keyD = datum.d;
|
|
716
732
|
switch (event.key) {
|
|
717
733
|
case 'ArrowUp':
|
|
718
|
-
|
|
719
|
-
k *= event.shiftKey ? 0.95 : 0.85;
|
|
734
|
+
keyA += event.shiftKey ? 1 : 5;
|
|
720
735
|
break;
|
|
721
736
|
case 'ArrowDown':
|
|
737
|
+
keyA -= event.shiftKey ? 1 : 5;
|
|
738
|
+
break;
|
|
722
739
|
case 'ArrowRight':
|
|
723
|
-
|
|
740
|
+
keyD += event.shiftKey ? 1 : 5;
|
|
741
|
+
break;
|
|
742
|
+
case 'ArrowLeft':
|
|
743
|
+
keyD -= event.shiftKey ? 1 : 5;
|
|
724
744
|
break;
|
|
725
745
|
default:
|
|
726
746
|
// no-op
|
|
727
747
|
}
|
|
728
|
-
|
|
729
|
-
?
|
|
730
|
-
: (
|
|
731
|
-
?
|
|
732
|
-
:
|
|
733
|
-
|
|
734
|
-
this.
|
|
748
|
+
keyD = (keyD < this.scale.time.min)
|
|
749
|
+
? this.scale.time.min
|
|
750
|
+
: ((keyD > this.scale.time.max)
|
|
751
|
+
? this.scale.time.max
|
|
752
|
+
: keyD);
|
|
753
|
+
keyA = (keyA < this.scale.value.min)
|
|
754
|
+
? this.scale.value.min
|
|
755
|
+
: ((keyA > this.scale.value.max)
|
|
756
|
+
? this.scale.value.max
|
|
757
|
+
: keyA);
|
|
758
|
+
if ((keyD !== datum.d) || (keyA !== datum.a)) {
|
|
759
|
+
datum.d = keyD;
|
|
760
|
+
datum.a = keyA;
|
|
761
|
+
if (datum.name === 'default') {
|
|
762
|
+
this.d = datum.d;
|
|
763
|
+
this.a = datum.a;
|
|
764
|
+
}
|
|
735
765
|
this.alignState();
|
|
736
766
|
this.requestUpdate();
|
|
737
767
|
this.dispatchEvent(new CustomEvent('htd-curves-change', {
|
|
@@ -748,14 +778,8 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
748
778
|
event.preventDefault();
|
|
749
779
|
}
|
|
750
780
|
});
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
.filter((datum, index, nodes) => {
|
|
754
|
-
return (this.interactive && !datum.trial && !d3.select(nodes[index]).select('.bar').classed('interactive'));
|
|
755
|
-
})
|
|
756
|
-
.select('.bar')
|
|
757
|
-
.classed('interactive', true)
|
|
758
|
-
.attr('tabindex', 0)
|
|
781
|
+
// Fill
|
|
782
|
+
bodyMergeInteractive.select('.fill')
|
|
759
783
|
// Drag interaction
|
|
760
784
|
.call(d3.drag()
|
|
761
785
|
.subject((event, datum) => {
|
|
@@ -771,13 +795,20 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
771
795
|
.on('drag', (event, datum) => {
|
|
772
796
|
this.drag = true;
|
|
773
797
|
const d = xScale.invert(event.x);
|
|
798
|
+
const a = yScale.invert(event.y);
|
|
774
799
|
datum.d = (d < this.scale.time.min)
|
|
775
800
|
? this.scale.time.min
|
|
776
801
|
: (d > this.scale.time.max)
|
|
777
802
|
? this.scale.time.max
|
|
778
803
|
: this.scale.time.round(d);
|
|
804
|
+
datum.a = (a < this.scale.value.min)
|
|
805
|
+
? this.scale.value.min
|
|
806
|
+
: (a > this.scale.value.max)
|
|
807
|
+
? this.scale.value.max
|
|
808
|
+
: this.scale.value.round(a);
|
|
779
809
|
if (datum.name === 'default') {
|
|
780
810
|
this.d = datum.d;
|
|
811
|
+
this.a = datum.a;
|
|
781
812
|
}
|
|
782
813
|
this.alignState();
|
|
783
814
|
this.requestUpdate();
|
|
@@ -795,55 +826,57 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
795
826
|
.on('end', (event) => {
|
|
796
827
|
const element = event.currentTarget;
|
|
797
828
|
d3.select(element).classed('dragging', false);
|
|
798
|
-
}))
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
this.alignState();
|
|
824
|
-
this.requestUpdate();
|
|
825
|
-
this.dispatchEvent(new CustomEvent('htd-curves-change', {
|
|
826
|
-
detail: {
|
|
827
|
-
name: datum.name,
|
|
828
|
-
a: datum.a,
|
|
829
|
-
d: datum.d,
|
|
830
|
-
k: this.k,
|
|
831
|
-
label: datum.label,
|
|
832
|
-
},
|
|
833
|
-
bubbles: true,
|
|
834
|
-
}));
|
|
829
|
+
}));
|
|
830
|
+
// Bar
|
|
831
|
+
bodyMergeInteractive.select('.bar')
|
|
832
|
+
// Drag interaction
|
|
833
|
+
.call(d3.drag()
|
|
834
|
+
.subject((event, datum) => {
|
|
835
|
+
return {
|
|
836
|
+
x: xScale(datum.d),
|
|
837
|
+
y: yScale(datum.a),
|
|
838
|
+
};
|
|
839
|
+
})
|
|
840
|
+
.on('start', (event) => {
|
|
841
|
+
const element = event.currentTarget;
|
|
842
|
+
d3.select(element).classed('dragging', true);
|
|
843
|
+
})
|
|
844
|
+
.on('drag', (event, datum) => {
|
|
845
|
+
this.drag = true;
|
|
846
|
+
const d = xScale.invert(event.x);
|
|
847
|
+
datum.d = (d < this.scale.time.min)
|
|
848
|
+
? this.scale.time.min
|
|
849
|
+
: (d > this.scale.time.max)
|
|
850
|
+
? this.scale.time.max
|
|
851
|
+
: this.scale.time.round(d);
|
|
852
|
+
if (datum.name === 'default') {
|
|
853
|
+
this.d = datum.d;
|
|
835
854
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
855
|
+
this.alignState();
|
|
856
|
+
this.requestUpdate();
|
|
857
|
+
this.dispatchEvent(new CustomEvent('htd-curves-change', {
|
|
858
|
+
detail: {
|
|
859
|
+
name: datum.name,
|
|
860
|
+
a: datum.a,
|
|
861
|
+
d: datum.d,
|
|
862
|
+
k: this.k,
|
|
863
|
+
label: datum.label,
|
|
864
|
+
},
|
|
865
|
+
bubbles: true,
|
|
866
|
+
}));
|
|
867
|
+
})
|
|
868
|
+
.on('end', (event) => {
|
|
869
|
+
const element = event.currentTarget;
|
|
870
|
+
d3.select(element).classed('dragging', false);
|
|
871
|
+
}));
|
|
839
872
|
// Point
|
|
840
873
|
optionMerge
|
|
841
874
|
.filter((datum, index, nodes) => {
|
|
842
|
-
return (this.interactive && !datum.trial && !d3.select(nodes[index]).select('.point').classed('
|
|
875
|
+
return (this.interactive && !datum.trial && !d3.select(nodes[index]).select('.top-point').classed('interact'));
|
|
843
876
|
})
|
|
844
|
-
.select('.point')
|
|
845
|
-
.classed('
|
|
846
|
-
.attr('tabindex',
|
|
877
|
+
.select('.top-point')
|
|
878
|
+
.classed('interact', true)
|
|
879
|
+
.attr('tabindex', -1)
|
|
847
880
|
// Drag interaction
|
|
848
881
|
.call(d3.drag()
|
|
849
882
|
.subject((event, datum) => {
|
|
@@ -886,8 +919,9 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
886
919
|
}))
|
|
887
920
|
// Keyboard interaction
|
|
888
921
|
.on('keydown', (event, datum) => {
|
|
889
|
-
if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
922
|
+
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
|
890
923
|
let keyA = datum.a;
|
|
924
|
+
let keyD = datum.d;
|
|
891
925
|
switch (event.key) {
|
|
892
926
|
case 'ArrowUp':
|
|
893
927
|
keyA += event.shiftKey ? 1 : 5;
|
|
@@ -895,17 +929,30 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
895
929
|
case 'ArrowDown':
|
|
896
930
|
keyA -= event.shiftKey ? 1 : 5;
|
|
897
931
|
break;
|
|
932
|
+
case 'ArrowRight':
|
|
933
|
+
keyD += event.shiftKey ? 1 : 5;
|
|
934
|
+
break;
|
|
935
|
+
case 'ArrowLeft':
|
|
936
|
+
keyD -= event.shiftKey ? 1 : 5;
|
|
937
|
+
break;
|
|
898
938
|
default:
|
|
899
939
|
// no-op
|
|
900
940
|
}
|
|
941
|
+
keyD = (keyD < this.scale.time.min)
|
|
942
|
+
? this.scale.time.min
|
|
943
|
+
: ((keyD > this.scale.time.max)
|
|
944
|
+
? this.scale.time.max
|
|
945
|
+
: keyD);
|
|
901
946
|
keyA = (keyA < this.scale.value.min)
|
|
902
947
|
? this.scale.value.min
|
|
903
948
|
: ((keyA > this.scale.value.max)
|
|
904
949
|
? this.scale.value.max
|
|
905
950
|
: keyA);
|
|
906
|
-
if (keyA !== datum.a) {
|
|
951
|
+
if ((keyD !== datum.d) || (keyA !== datum.a)) {
|
|
952
|
+
datum.d = keyD;
|
|
907
953
|
datum.a = keyA;
|
|
908
954
|
if (datum.name === 'default') {
|
|
955
|
+
this.d = datum.d;
|
|
909
956
|
this.a = datum.a;
|
|
910
957
|
}
|
|
911
958
|
this.alignState();
|
|
@@ -924,115 +971,212 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
924
971
|
event.preventDefault();
|
|
925
972
|
}
|
|
926
973
|
});
|
|
927
|
-
|
|
928
|
-
// Non-interactive options
|
|
929
974
|
// Curve
|
|
930
975
|
optionMerge
|
|
931
976
|
.filter((datum, index, nodes) => {
|
|
932
|
-
return (
|
|
977
|
+
return (this.interactive && !d3.select(nodes[index]).select('.curve').classed('interactive'));
|
|
933
978
|
})
|
|
934
979
|
.select('.curve')
|
|
935
|
-
.classed('interactive',
|
|
980
|
+
.classed('interactive', true)
|
|
981
|
+
.attr('tabindex', 0)
|
|
982
|
+
// Drag interaction
|
|
983
|
+
.call(d3.drag()
|
|
984
|
+
.subject((event) => {
|
|
985
|
+
return {
|
|
986
|
+
x: event.x,
|
|
987
|
+
y: event.y,
|
|
988
|
+
};
|
|
989
|
+
})
|
|
990
|
+
.on('start', (event) => {
|
|
991
|
+
const element = event.currentTarget;
|
|
992
|
+
d3.select(element).classed('dragging', true);
|
|
993
|
+
})
|
|
994
|
+
.on('drag', (event, datum) => {
|
|
995
|
+
this.drag = true;
|
|
996
|
+
const dragD = datum.d - xScale.invert(event.x);
|
|
997
|
+
const d = (dragD < 0)
|
|
998
|
+
? 0
|
|
999
|
+
: (dragD > datum.d)
|
|
1000
|
+
? datum.d
|
|
1001
|
+
: dragD;
|
|
1002
|
+
const dragV = yScale.invert(event.y);
|
|
1003
|
+
const v = (dragV <= 0)
|
|
1004
|
+
? 0.001
|
|
1005
|
+
: (dragV > datum.a)
|
|
1006
|
+
? datum.a
|
|
1007
|
+
: dragV;
|
|
1008
|
+
const k = HTDMath.adv2k(datum.a, d, v);
|
|
1009
|
+
this.k = (k < HTDMath.k.MIN)
|
|
1010
|
+
? HTDMath.k.MIN
|
|
1011
|
+
: (k > HTDMath.k.MAX)
|
|
1012
|
+
? HTDMath.k.MAX
|
|
1013
|
+
: k;
|
|
1014
|
+
this.alignState();
|
|
1015
|
+
this.requestUpdate();
|
|
1016
|
+
this.dispatchEvent(new CustomEvent('htd-curves-change', {
|
|
1017
|
+
detail: {
|
|
1018
|
+
name: datum.name,
|
|
1019
|
+
a: datum.a,
|
|
1020
|
+
d: datum.d,
|
|
1021
|
+
k: this.k,
|
|
1022
|
+
label: datum.label,
|
|
1023
|
+
},
|
|
1024
|
+
bubbles: true,
|
|
1025
|
+
}));
|
|
1026
|
+
})
|
|
1027
|
+
.on('end', (event) => {
|
|
1028
|
+
const element = event.currentTarget;
|
|
1029
|
+
d3.select(element).classed('dragging', false);
|
|
1030
|
+
}))
|
|
1031
|
+
// Keyboard interaction
|
|
1032
|
+
.on('keydown', (event, datum) => {
|
|
1033
|
+
if (['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft'].includes(event.key)) {
|
|
1034
|
+
let {k} = this;
|
|
1035
|
+
switch (event.key) {
|
|
1036
|
+
case 'ArrowUp':
|
|
1037
|
+
case 'ArrowLeft':
|
|
1038
|
+
k *= event.shiftKey ? 0.95 : 0.85;
|
|
1039
|
+
break;
|
|
1040
|
+
case 'ArrowDown':
|
|
1041
|
+
case 'ArrowRight':
|
|
1042
|
+
k *= event.shiftKey ? (1 / 0.95) : (1 / 0.85);
|
|
1043
|
+
break;
|
|
1044
|
+
default:
|
|
1045
|
+
// no-op
|
|
1046
|
+
}
|
|
1047
|
+
k = (k < HTDMath.k.MIN)
|
|
1048
|
+
? HTDMath.k.MIN
|
|
1049
|
+
: (k > HTDMath.k.MAX)
|
|
1050
|
+
? HTDMath.k.MAX
|
|
1051
|
+
: k;
|
|
1052
|
+
if (k !== this.k) {
|
|
1053
|
+
this.k = k;
|
|
1054
|
+
this.alignState();
|
|
1055
|
+
this.requestUpdate();
|
|
1056
|
+
this.dispatchEvent(new CustomEvent('htd-curves-change', {
|
|
1057
|
+
detail: {
|
|
1058
|
+
name: datum.name,
|
|
1059
|
+
a: datum.a,
|
|
1060
|
+
d: datum.d,
|
|
1061
|
+
k: this.k,
|
|
1062
|
+
label: datum.label,
|
|
1063
|
+
},
|
|
1064
|
+
bubbles: true,
|
|
1065
|
+
}));
|
|
1066
|
+
}
|
|
1067
|
+
event.preventDefault();
|
|
1068
|
+
}
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
// Non-interactive options
|
|
1072
|
+
// Body (Fill, Bar, Point)
|
|
1073
|
+
const bodyMergeNoninteractive = optionMerge
|
|
1074
|
+
.filter((datum, index, nodes) => {
|
|
1075
|
+
return ((!this.interactive || datum.trial) && d3.select(nodes[index]).select('.body').classed('interactive'));
|
|
1076
|
+
});
|
|
1077
|
+
bodyMergeNoninteractive.classed('interactive', false);
|
|
1078
|
+
// Fill
|
|
1079
|
+
bodyMergeNoninteractive
|
|
1080
|
+
.select('.fill')
|
|
936
1081
|
.attr('tabindex', null)
|
|
937
1082
|
.on('drag', null)
|
|
938
1083
|
.on('keydown', null);
|
|
939
1084
|
// Bar
|
|
1085
|
+
bodyMergeNoninteractive
|
|
1086
|
+
.select('.bar')
|
|
1087
|
+
.on('drag', null)
|
|
1088
|
+
.on('keydown', null);
|
|
1089
|
+
// Point
|
|
940
1090
|
optionMerge
|
|
941
1091
|
.filter((datum, index, nodes) => {
|
|
942
|
-
return ((!this.interactive || datum.trial) && d3.select(nodes[index]).select('.
|
|
1092
|
+
return ((!this.interactive || datum.trial) && d3.select(nodes[index]).select('.top-point').classed('interact'));
|
|
943
1093
|
})
|
|
944
|
-
.select('.
|
|
945
|
-
.classed('
|
|
946
|
-
.attr('tabindex', null)
|
|
1094
|
+
.select('.top-point')
|
|
1095
|
+
.classed('interact', false)
|
|
947
1096
|
.on('drag', null)
|
|
948
1097
|
.on('keydown', null);
|
|
949
|
-
//
|
|
1098
|
+
// Curve
|
|
950
1099
|
optionMerge
|
|
951
1100
|
.filter((datum, index, nodes) => {
|
|
952
|
-
return (
|
|
1101
|
+
return (!this.interactive && d3.select(nodes[index]).select('.curve').classed('interactive'));
|
|
953
1102
|
})
|
|
954
|
-
.select('.
|
|
1103
|
+
.select('.curve')
|
|
955
1104
|
.classed('interactive', false)
|
|
956
1105
|
.attr('tabindex', null)
|
|
957
1106
|
.on('drag', null)
|
|
958
1107
|
.on('keydown', null);
|
|
959
1108
|
|
|
960
1109
|
// Trial Animation
|
|
961
|
-
//
|
|
1110
|
+
// Fill
|
|
962
1111
|
optionMerge
|
|
963
1112
|
.filter((datum) => {
|
|
964
1113
|
return (datum.new);
|
|
965
1114
|
})
|
|
966
|
-
.
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
})
|
|
974
|
-
.on('end', (datum) => {
|
|
975
|
-
datum.new = false;
|
|
976
|
-
this.dispatchEvent(new CustomEvent('discountable-response', {
|
|
977
|
-
detail: {
|
|
978
|
-
trial: this.trialCount,
|
|
979
|
-
as: this.as,
|
|
980
|
-
ds: this.ds,
|
|
981
|
-
al: this.al,
|
|
982
|
-
dl: this.dl,
|
|
983
|
-
response: this.response,
|
|
984
|
-
},
|
|
985
|
-
bubbles: true,
|
|
986
|
-
}));
|
|
1115
|
+
.each(() => {
|
|
1116
|
+
svgMerge
|
|
1117
|
+
.selectAll('.gradient .animation').transition()
|
|
1118
|
+
.duration(transitionDuration)
|
|
1119
|
+
.delay(transitionDuration + transitionDuration / 10)
|
|
1120
|
+
.ease(d3.easeLinear)
|
|
1121
|
+
.attrTween('offset', () => { return d3.interpolate(1, 0); });
|
|
987
1122
|
});
|
|
1123
|
+
// Bar
|
|
988
1124
|
optionMerge
|
|
989
1125
|
.filter((datum) => {
|
|
990
1126
|
return (datum.new);
|
|
991
1127
|
})
|
|
992
|
-
.
|
|
1128
|
+
.selectAll('.bar .line').transition()
|
|
993
1129
|
.duration(transitionDuration)
|
|
994
|
-
.delay(transitionDuration + transitionDuration / 10)
|
|
995
1130
|
.ease(d3.easeLinear)
|
|
996
1131
|
.attrTween('stroke-dasharray', (datum, index, nodes) => {
|
|
997
1132
|
const length = nodes[index].getTotalLength();
|
|
998
|
-
return d3.interpolate(`0,${length}`, `${length},${
|
|
1133
|
+
return d3.interpolate(`0,${length}`, `${length},${length}`);
|
|
999
1134
|
});
|
|
1000
|
-
//
|
|
1135
|
+
// Point
|
|
1001
1136
|
optionMerge
|
|
1002
1137
|
.filter((datum) => {
|
|
1003
1138
|
return (datum.new);
|
|
1004
1139
|
})
|
|
1005
|
-
.
|
|
1006
|
-
.duration(transitionDuration)
|
|
1140
|
+
.selectAll('.point').transition()
|
|
1141
|
+
.duration(transitionDuration / 10)
|
|
1142
|
+
.delay(transitionDuration)
|
|
1007
1143
|
.ease(d3.easeLinear)
|
|
1008
|
-
.attrTween('
|
|
1009
|
-
|
|
1010
|
-
return d3.interpolate(`0,${length}`, `${length},${length}`);
|
|
1011
|
-
});
|
|
1144
|
+
.attrTween('opacity', () => { return d3.interpolate(0, 1); });
|
|
1145
|
+
// Curve
|
|
1012
1146
|
optionMerge
|
|
1013
1147
|
.filter((datum) => {
|
|
1014
1148
|
return (datum.new);
|
|
1015
1149
|
})
|
|
1016
|
-
.
|
|
1150
|
+
.selectAll('.curve .path').transition()
|
|
1017
1151
|
.duration(transitionDuration)
|
|
1152
|
+
.delay(transitionDuration + transitionDuration / 10)
|
|
1018
1153
|
.ease(d3.easeLinear)
|
|
1019
1154
|
.attrTween('stroke-dasharray', (datum, index, nodes) => {
|
|
1020
1155
|
const length = nodes[index].getTotalLength();
|
|
1021
|
-
return d3.interpolate(`0,${length}`, `${length},${
|
|
1022
|
-
});
|
|
1023
|
-
// Point
|
|
1024
|
-
optionMerge
|
|
1025
|
-
.filter((datum) => {
|
|
1026
|
-
return (datum.new);
|
|
1156
|
+
return d3.interpolate(`0,${length}`, `${length},${0}`);
|
|
1027
1157
|
})
|
|
1028
|
-
.
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1158
|
+
.on('end', (datum) => {
|
|
1159
|
+
datum.new = false;
|
|
1160
|
+
this.dispatchEvent(new CustomEvent('discountable-response', {
|
|
1161
|
+
detail: {
|
|
1162
|
+
trial: this.trialCount,
|
|
1163
|
+
as: this.as,
|
|
1164
|
+
ds: this.ds,
|
|
1165
|
+
al: this.al,
|
|
1166
|
+
dl: this.dl,
|
|
1167
|
+
response: this.response,
|
|
1168
|
+
},
|
|
1169
|
+
bubbles: true,
|
|
1170
|
+
}));
|
|
1171
|
+
});
|
|
1033
1172
|
|
|
1034
1173
|
// All options
|
|
1035
|
-
|
|
1174
|
+
optionMerge.filter((datum) => { return datum.label === 's'; })
|
|
1175
|
+
.raise();
|
|
1176
|
+
optionMerge.filter((datum) => { return datum.label === 'l'; })
|
|
1177
|
+
.lower();
|
|
1178
|
+
// Fill
|
|
1179
|
+
optionUpdate.select('.fill .region').transition()
|
|
1036
1180
|
.duration(this.drag
|
|
1037
1181
|
? 0
|
|
1038
1182
|
: (this.firstUpdate
|
|
@@ -1062,43 +1206,11 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
1062
1206
|
),
|
|
1063
1207
|
};
|
|
1064
1208
|
});
|
|
1065
|
-
return line(curve);
|
|
1209
|
+
return line([...curve, {d: 0, v: 0}, {d: element.d, v: 0}]);
|
|
1066
1210
|
};
|
|
1067
1211
|
});
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
? 0
|
|
1071
|
-
: (this.firstUpdate
|
|
1072
|
-
? (transitionDuration * 2)
|
|
1073
|
-
: transitionDuration))
|
|
1074
|
-
.ease(d3.easeCubicOut)
|
|
1075
|
-
.attrTween('d', (datum, index, elements) => {
|
|
1076
|
-
const element = elements[index];
|
|
1077
|
-
const interpolateA = d3.interpolate(
|
|
1078
|
-
(element.a !== undefined) ? element.a : datum.a,
|
|
1079
|
-
datum.a,
|
|
1080
|
-
);
|
|
1081
|
-
const interpolateD = d3.interpolate(
|
|
1082
|
-
(element.d !== undefined) ? element.d : datum.d,
|
|
1083
|
-
datum.d,
|
|
1084
|
-
);
|
|
1085
|
-
return (time) => {
|
|
1086
|
-
element.a = interpolateA(time);
|
|
1087
|
-
element.d = interpolateD(time);
|
|
1088
|
-
const curve = d3.range(xScale(element.d), xScale(0), -1).map((range) => {
|
|
1089
|
-
return {
|
|
1090
|
-
d: xScale.invert(range),
|
|
1091
|
-
v: HTDMath.adk2v(
|
|
1092
|
-
element.a,
|
|
1093
|
-
element.d - xScale.invert(range),
|
|
1094
|
-
this.k,
|
|
1095
|
-
),
|
|
1096
|
-
};
|
|
1097
|
-
});
|
|
1098
|
-
return line(curve);
|
|
1099
|
-
};
|
|
1100
|
-
});
|
|
1101
|
-
optionUpdate.select('.bar .line').transition()
|
|
1212
|
+
// Bar
|
|
1213
|
+
optionUpdate.selectAll('.bar .line').transition()
|
|
1102
1214
|
.duration(this.drag
|
|
1103
1215
|
? 0
|
|
1104
1216
|
: (this.firstUpdate
|
|
@@ -1138,71 +1250,66 @@ export default class HTDCurves extends DecidablesMixinResizeable(DiscountableEle
|
|
|
1138
1250
|
return `${yScale(element.a)}`;
|
|
1139
1251
|
};
|
|
1140
1252
|
});
|
|
1141
|
-
|
|
1253
|
+
// Point
|
|
1254
|
+
optionUpdate.selectAll('.point').transition()
|
|
1142
1255
|
.duration(this.drag
|
|
1143
1256
|
? 0
|
|
1144
1257
|
: (this.firstUpdate
|
|
1145
1258
|
? (transitionDuration * 2)
|
|
1146
1259
|
: transitionDuration))
|
|
1147
1260
|
.ease(d3.easeCubicOut)
|
|
1148
|
-
.attrTween('
|
|
1149
|
-
const element = elements[index];
|
|
1150
|
-
const interpolateD = d3.interpolate(
|
|
1151
|
-
(element.d !== undefined) ? element.d : datum.d,
|
|
1152
|
-
datum.d,
|
|
1153
|
-
);
|
|
1154
|
-
return (time) => {
|
|
1155
|
-
element.d = interpolateD(time);
|
|
1156
|
-
return `${xScale(element.d)}`;
|
|
1157
|
-
};
|
|
1158
|
-
})
|
|
1159
|
-
.attrTween('x2', (datum, index, elements) => {
|
|
1261
|
+
.attrTween('transform', (datum, index, elements) => {
|
|
1160
1262
|
const element = elements[index];
|
|
1161
1263
|
const interpolateD = d3.interpolate(
|
|
1162
1264
|
(element.d !== undefined) ? element.d : datum.d,
|
|
1163
1265
|
datum.d,
|
|
1164
1266
|
);
|
|
1165
|
-
return (time) => {
|
|
1166
|
-
element.d = interpolateD(time);
|
|
1167
|
-
return `${xScale(element.d)}`;
|
|
1168
|
-
};
|
|
1169
|
-
})
|
|
1170
|
-
.attrTween('y2', (datum, index, elements) => {
|
|
1171
|
-
const element = elements[index];
|
|
1172
1267
|
const interpolateA = d3.interpolate(
|
|
1173
1268
|
(element.a !== undefined) ? element.a : datum.a,
|
|
1174
1269
|
datum.a,
|
|
1175
1270
|
);
|
|
1176
1271
|
return (time) => {
|
|
1272
|
+
element.d = interpolateD(time);
|
|
1177
1273
|
element.a = interpolateA(time);
|
|
1178
|
-
return
|
|
1274
|
+
return `translate(${xScale(element.d)}, ${yScale(element.a)})`;
|
|
1179
1275
|
};
|
|
1180
1276
|
});
|
|
1181
|
-
|
|
1277
|
+
optionMerge.select('.point .label')
|
|
1278
|
+
.text((datum) => { return datum.label; });
|
|
1279
|
+
// Curve
|
|
1280
|
+
optionUpdate.selectAll('.curve .path').transition()
|
|
1182
1281
|
.duration(this.drag
|
|
1183
1282
|
? 0
|
|
1184
1283
|
: (this.firstUpdate
|
|
1185
1284
|
? (transitionDuration * 2)
|
|
1186
1285
|
: transitionDuration))
|
|
1187
1286
|
.ease(d3.easeCubicOut)
|
|
1188
|
-
.attrTween('
|
|
1287
|
+
.attrTween('d', (datum, index, elements) => {
|
|
1189
1288
|
const element = elements[index];
|
|
1190
|
-
const interpolateD = d3.interpolate(
|
|
1191
|
-
(element.d !== undefined) ? element.d : datum.d,
|
|
1192
|
-
datum.d,
|
|
1193
|
-
);
|
|
1194
1289
|
const interpolateA = d3.interpolate(
|
|
1195
1290
|
(element.a !== undefined) ? element.a : datum.a,
|
|
1196
1291
|
datum.a,
|
|
1197
1292
|
);
|
|
1293
|
+
const interpolateD = d3.interpolate(
|
|
1294
|
+
(element.d !== undefined) ? element.d : datum.d,
|
|
1295
|
+
datum.d,
|
|
1296
|
+
);
|
|
1198
1297
|
return (time) => {
|
|
1199
|
-
element.d = interpolateD(time);
|
|
1200
1298
|
element.a = interpolateA(time);
|
|
1201
|
-
|
|
1299
|
+
element.d = interpolateD(time);
|
|
1300
|
+
const curve = d3.range(xScale(element.d), xScale(0), -1).map((range) => {
|
|
1301
|
+
return {
|
|
1302
|
+
d: xScale.invert(range),
|
|
1303
|
+
v: HTDMath.adk2v(
|
|
1304
|
+
element.a,
|
|
1305
|
+
element.d - xScale.invert(range),
|
|
1306
|
+
this.k,
|
|
1307
|
+
),
|
|
1308
|
+
};
|
|
1309
|
+
});
|
|
1310
|
+
return line(curve);
|
|
1202
1311
|
};
|
|
1203
1312
|
});
|
|
1204
|
-
optionMerge.select('.point .label')
|
|
1205
|
-
.text((datum) => { return datum.label; });
|
|
1206
1313
|
// EXIT
|
|
1207
1314
|
// NOTE: Could add a transition here
|
|
1208
1315
|
optionUpdate.exit().remove();
|