@decidables/accumulable-elements 0.3.3 → 0.3.5

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.
@@ -8111,8 +8111,13 @@
8111
8111
  }
8112
8112
  }
8113
8113
 
8114
- .measure {
8115
- stroke-width: 2;
8114
+ .measure .line.short {
8115
+ stroke-width: 0;
8116
+ }
8117
+
8118
+ .measure .markers {
8119
+ fill: none;
8120
+ stroke-width: 0;
8116
8121
  }
8117
8122
 
8118
8123
  .measure .label {
@@ -8134,7 +8139,9 @@
8134
8139
  stroke: var(---color-z);
8135
8140
  }
8136
8141
 
8137
- .measure.z .label {
8142
+ .measure.z .label,
8143
+ /* Hack to avoid Safari weirdness */
8144
+ .measure.z .label tspan {
8138
8145
  dominant-baseline: hanging;
8139
8146
  text-anchor: start;
8140
8147
  }
@@ -8157,6 +8164,43 @@
8157
8164
  text-anchor: middle;
8158
8165
  }
8159
8166
 
8167
+ .measure-arrow {
8168
+ fill: context-stroke;
8169
+ stroke: context-stroke;
8170
+ }
8171
+
8172
+ .measure-arrow .arrow {
8173
+ stroke-width: 1;
8174
+ }
8175
+
8176
+ .measure-arrow.capped .cap {
8177
+ stroke-width: 2;
8178
+ }
8179
+
8180
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8181
+ .measure-arrow.a {
8182
+ fill: var(---color-a);
8183
+ stroke: var(---color-a);
8184
+ }
8185
+
8186
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8187
+ .measure-arrow.z {
8188
+ fill: var(---color-z);
8189
+ stroke: var(---color-z);
8190
+ }
8191
+
8192
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8193
+ .measure-arrow.v {
8194
+ fill: var(---color-v);
8195
+ stroke: var(---color-v);
8196
+ }
8197
+
8198
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8199
+ .measure-arrow.t0 {
8200
+ fill: var(---color-t0);
8201
+ stroke: var(---color-t0);
8202
+ }
8203
+
8160
8204
  .sd .indicator,
8161
8205
  .mean .indicator {
8162
8206
  stroke-width: 2;
@@ -8182,6 +8226,20 @@
8182
8226
  stroke: var(---color-error-dark);
8183
8227
  }
8184
8228
 
8229
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8230
+ .cap.correct {
8231
+ fill: var(---color-correct-dark);
8232
+ stroke: var(---color-correct-dark);
8233
+ stroke-dasharray: 100%;
8234
+ }
8235
+
8236
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8237
+ .cap.error {
8238
+ fill: var(---color-error-dark);
8239
+ stroke: var(---color-error-dark);
8240
+ stroke-dasharray: 100%;
8241
+ }
8242
+
8185
8243
  .rt-label rect {
8186
8244
  filter: url("#shadow-2");
8187
8245
 
@@ -8401,10 +8459,29 @@
8401
8459
  const svgEnter = svgUpdate.enter().append('svg').classed('main', true).html(AccumulableElement.svgDefs);
8402
8460
  const svgDefs = svgEnter.append('defs');
8403
8461
  // Arrowhead marker for measures
8404
- svgDefs.append('marker').attr('id', 'measure-arrow').attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-5 -5 10 10').attr('refX', '2').attr('refY', '0').attr('markerWidth', '10').attr('markerHeight', '10').append('path').attr('stroke', 'context-stroke').attr('fill', 'context-stroke').attr('d', 'M -3 -3 l 6 3 l -6 3 z');
8462
+ const measureArrow = parameter => {
8463
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8464
+ svgDefs.append('marker').attr('id', `measure-arrow-${parameter}`).attr('class', `measure-arrow ${parameter}`).attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-10 -6 12 12').attr('refX', '0').attr('refY', '0').attr('markerWidth', '12').attr('markerHeight', '12').append('path').attr('class', 'arrow').attr('d', 'M -7 -3 l 6 3 l -6 3 z');
8465
+ };
8466
+ const measureCappedArrow = parameter => {
8467
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8468
+ const marker = svgDefs.append('marker').attr('id', `measure-capped-arrow-${parameter}`).attr('class', `measure-arrow capped ${parameter}`).attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-10 -6 12 12').attr('refX', '0').attr('refY', '0').attr('markerWidth', '12').attr('markerHeight', '12');
8469
+ marker.append('path').attr('class', 'arrow').attr('d', 'M -7 -3 l 6 3 l -6 3 z');
8470
+ marker.append('path').attr('class', 'cap').attr('d', 'M 0 -4 l 0 8');
8471
+ };
8472
+ measureArrow('a');
8473
+ measureArrow('z');
8474
+ measureCappedArrow('v');
8475
+ measureArrow('t0');
8476
+ measureCappedArrow('t0');
8405
8477
  // Flat markers for SDs
8406
- svgDefs.append('marker').attr('id', 'model-sd-cap').attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-5 -5 10 10').attr('refX', '0').attr('refY', '0').attr('markerWidth', '10').attr('markerHeight', '10').append('path').attr('stroke', 'context-stroke').attr('fill', 'context-stroke').attr('stroke-width', '2').attr('d', 'M 0 -4 l 0 8');
8407
- svgDefs.append('marker').attr('id', 'data-sd-cap').attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-5 -5 10 10').attr('refX', '0').attr('refY', '0').attr('markerWidth', '10').attr('markerHeight', '10').append('path').attr('stroke', 'context-stroke').attr('fill', 'context-stroke').attr('stroke-width', '2').attr('d', 'M 0 -3 l 0 6');
8478
+ const sdCap = outcome => {
8479
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */
8480
+ svgDefs.append('marker').attr('id', `model-sd-cap-${outcome}`).attr('class', `model-sd cap ${outcome}`).attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-5 -5 10 10').attr('refX', '0').attr('refY', '0').attr('markerWidth', '10').attr('markerHeight', '10').append('path').attr('stroke', 'context-stroke').attr('fill', 'context-stroke').attr('stroke-width', '2').attr('d', 'M 0 -4 l 0 8');
8481
+ svgDefs.append('marker').attr('id', `data-sd-cap-${outcome}`).attr('class', `data-sd cap ${outcome}`).attr('orient', 'auto-start-reverse').attr('markerUnits', 'userSpaceOnUse').attr('viewBox', '-5 -5 10 10').attr('refX', '0').attr('refY', '0').attr('markerWidth', '10').attr('markerHeight', '10').append('path').attr('stroke', 'context-stroke').attr('fill', 'context-stroke').attr('stroke-width', '2').attr('d', 'M 0 -3 l 0 6');
8482
+ };
8483
+ sdCap('error');
8484
+ sdCap('correct');
8408
8485
  const gradient = svgDefs.append('linearGradient').attr('id', 'path-animate').attr('gradientUnits', 'userSpaceOnUse').attr('color-interpolation', 'linearRGB').attr('x1', '0').attr('x2', '0').attr('y1', evidenceScale(this.bounds.upper)).attr('y2', evidenceScale(this.bounds.lower));
8409
8486
  gradient.append('stop').classed('stop-0', true).attr('offset', '0%');
8410
8487
  gradient.append('stop').classed('stop-100', true).attr('offset', '100%');
@@ -8992,19 +9069,27 @@
8992
9069
  // EXIT
8993
9070
  t0zUpdate.exit().remove();
8994
9071
 
9072
+ // Measures
9073
+ const markerCorrection = 2;
9074
+
8995
9075
  // a Measure
8996
9076
  // DATA-JOIN
8997
9077
  const aUpdate = evidenceOverlayerMerge.selectAll('.measure.a').data(this.measures ? [this.a] : []);
8998
9078
  // ENTER
8999
9079
  const aEnter = aUpdate.enter().append('g').classed('measure a', true);
9000
- aEnter.append('line').classed('line', true).attr('marker-start', 'url(#measure-arrow)').attr('marker-end', 'url(#measure-arrow)');
9080
+ aEnter.append('line').classed('line', true);
9081
+ aEnter.append('line').classed('markers', true)
9082
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */.attr('marker-start', 'url(#measure-arrow-a)').attr('marker-end', 'url(#measure-arrow-a)');
9001
9083
  const aLabel = aEnter.append('text').classed('label', true);
9002
9084
  aLabel.append('tspan').classed('a math-var', true).text('a');
9003
9085
  aLabel.append('tspan').classed('equals', true).text(' = ');
9004
9086
  aLabel.append('tspan').classed('value', true);
9005
9087
  // MERGE
9088
+ const aLength = Math.abs(evidenceScale(this.bounds.upper) - evidenceScale(this.bounds.lower));
9089
+ const aShort = aLength <= markerCorrection * 2;
9006
9090
  const aMerge = aEnter.merge(aUpdate);
9007
- aMerge.select('.line').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(this.scale.time.max) - this.rem * 0.75).attr('y1', evidenceScale(this.bounds.upper) + 2).attr('x2', timeScale(this.scale.time.max) - this.rem * 0.75).attr('y2', evidenceScale(this.bounds.lower) - 2);
9091
+ aMerge.select('.line').classed('short', aShort).transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(this.scale.time.max) - this.rem * 0.75).attr('y1', evidenceScale(this.bounds.upper) + markerCorrection).attr('x2', timeScale(this.scale.time.max) - this.rem * 0.75).attr('y2', evidenceScale(this.bounds.lower) - markerCorrection);
9092
+ aMerge.select('.markers').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(this.scale.time.max) - this.rem * 0.75).attr('y1', evidenceScale(this.bounds.upper)).attr('x2', timeScale(this.scale.time.max) - this.rem * 0.75).attr('y2', evidenceScale(this.bounds.lower));
9008
9093
  const aLabelMerge = aMerge.select('.label').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x', timeScale(this.scale.time.max)).attr('y', evidenceScale(this.bounds.upper) - this.rem * 0.25);
9009
9094
  aLabelMerge.select('.value').text(format('.2f')(this.a));
9010
9095
  // EXIT
@@ -9015,14 +9100,19 @@
9015
9100
  const zUpdate = evidenceOverlayerMerge.selectAll('.measure.z').data(this.measures ? [this.z] : []);
9016
9101
  // ENTER
9017
9102
  const zEnter = zUpdate.enter().append('g').classed('measure z', true);
9018
- zEnter.append('line').classed('line', true).attr('marker-start', 'url(#measure-arrow)').attr('marker-end', 'url(#measure-arrow)');
9103
+ zEnter.append('line').classed('line', true);
9104
+ zEnter.append('line').classed('markers', true)
9105
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */.attr('marker-start', 'url(#measure-arrow-z)').attr('marker-end', 'url(#measure-arrow-z)');
9019
9106
  const zLabel = zEnter.append('text').classed('label', true);
9020
9107
  zLabel.append('tspan').classed('z math-var', true).text('z');
9021
9108
  zLabel.append('tspan').classed('equals', true).text(' = ');
9022
9109
  zLabel.append('tspan').classed('value', true);
9023
9110
  // MERGE
9111
+ const zLength = Math.abs(evidenceScale(this.startingPoint) - evidenceScale(this.bounds.lower));
9112
+ const zShort = zLength <= markerCorrection * 2;
9024
9113
  const zMerge = zEnter.merge(zUpdate);
9025
- zMerge.select('.line').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(this.scale.time.min) + this.rem * 0.75).attr('y1', evidenceScale(this.startingPoint) + 2).attr('x2', timeScale(this.scale.time.min) + this.rem * 0.75).attr('y2', evidenceScale(this.bounds.lower) - 2);
9114
+ zMerge.select('.line').classed('short', zShort).transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(this.scale.time.min) + this.rem * 0.75).attr('y1', evidenceScale(this.startingPoint) + markerCorrection).attr('x2', timeScale(this.scale.time.min) + this.rem * 0.75).attr('y2', evidenceScale(this.bounds.lower) - markerCorrection);
9115
+ zMerge.select('.markers').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(this.scale.time.min) + this.rem * 0.75).attr('y1', evidenceScale(this.startingPoint)).attr('x2', timeScale(this.scale.time.min) + this.rem * 0.75).attr('y2', evidenceScale(this.bounds.lower));
9026
9116
  const zLabelMerge = zMerge.select('.label').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x', timeScale(this.scale.time.min)).attr('y', evidenceScale(this.bounds.lower) + this.rem * 0.125);
9027
9117
  zLabelMerge.select('.value').text(format('.0%')(this.z));
9028
9118
  // EXIT
@@ -9033,20 +9123,37 @@
9033
9123
  const vUpdate = evidenceOverlayerMerge.selectAll('.measure.v').data(this.measures ? [this.v] : []);
9034
9124
  // ENTER
9035
9125
  const vEnter = vUpdate.enter().append('g').classed('measure v', true);
9036
- vEnter.append('path').classed('line', true).attr('marker-start', 'url(#measure-arrow)').attr('marker-end', 'url(#measure-arrow)');
9126
+ vEnter.append('path').classed('line', true);
9127
+ vEnter.append('path').classed('markers', true)
9128
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */.attr('marker-start', 'url(#measure-capped-arrow-v)').attr('marker-end', 'url(#measure-capped-arrow-v)');
9037
9129
  const vLabel = vEnter.append('text').classed('label', true);
9038
9130
  vLabel.append('tspan').classed('v math-var', true).text('v');
9039
9131
  vLabel.append('tspan').classed('equals', true).text(' = ');
9040
9132
  vLabel.append('tspan').classed('value', true);
9041
9133
  // MERGE
9042
- const driftAngle = Math.atan(this.v / 1000 * scaleRatio);
9134
+ // Full path
9043
9135
  const driftHypotenuse = timeScale(200) - timeScale(0) + this.rem * 0.75;
9136
+ const driftAngle = Math.atan(this.v / 1000 * scaleRatio);
9044
9137
  const driftX = Math.cos(driftAngle) * driftHypotenuse;
9045
9138
  const driftY = Math.sin(driftAngle) * driftHypotenuse;
9139
+ // Corrected path
9140
+ const driftCorrection = markerCorrection / driftHypotenuse;
9141
+ const driftAngleCorrected = Math.atan(this.v / 1000 * scaleRatio) - driftCorrection;
9142
+ const driftStartX = Math.cos(driftCorrection) * driftHypotenuse;
9143
+ const driftStartY = Math.sin(driftCorrection) * driftHypotenuse;
9144
+ const driftEndX = Math.cos(driftAngleCorrected) * driftHypotenuse;
9145
+ const driftEndY = Math.sin(driftAngleCorrected) * driftHypotenuse;
9146
+ // Short path?
9147
+ const vLength = driftAngleCorrected * driftHypotenuse;
9148
+ const vShort = vLength <= markerCorrection * 2;
9046
9149
  const vMerge = vEnter.merge(vUpdate);
9047
- vMerge.select('.line').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('d', `
9150
+ vMerge.select('.line').classed('short', vShort).transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('d', `
9151
+ M ${timeScale(this.t0) + driftStartX}, ${evidenceScale(this.startingPoint) - driftStartY}
9152
+ A ${timeScale(200) - timeScale(0) + this.rem * 0.75} ${timeScale(200) - timeScale(0) + this.rem * 0.75} 0 0 0 ${timeScale(this.t0) + driftEndX} ${evidenceScale(this.startingPoint) - driftEndY}
9153
+ `);
9154
+ vMerge.select('.markers').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('d', `
9048
9155
  M ${timeScale(this.t0 + 200) + this.rem * 0.75}, ${evidenceScale(this.startingPoint)}
9049
- A ${timeScale(200) - timeScale(0)} ${timeScale(200) - timeScale(0)} 0 0 0 ${timeScale(this.t0) + driftX} ${evidenceScale(this.startingPoint) - driftY}
9156
+ A ${timeScale(200) - timeScale(0) + this.rem * 0.75} ${timeScale(200) - timeScale(0) + this.rem * 0.75} 0 0 0 ${timeScale(this.t0) + driftX} ${evidenceScale(this.startingPoint) - driftY}
9050
9157
  `);
9051
9158
  const vLabelMerge = vMerge.select('.label').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x', timeScale(this.t0 + 200) + this.rem * 0.5).attr('y', evidenceScale(this.bounds.upper) - this.rem * 0.25);
9052
9159
  vLabelMerge.select('.value').text(format('.2f')(this.v));
@@ -9058,14 +9165,19 @@
9058
9165
  const t0Update = evidenceOverlayerMerge.selectAll('.measure.t0').data(this.measures ? [this.t0] : []);
9059
9166
  // ENTER
9060
9167
  const t0Enter = t0Update.enter().append('g').classed('measure t0', true);
9061
- t0Enter.append('line').classed('line', true).attr('marker-start', 'url(#measure-arrow)').attr('marker-end', 'url(#measure-arrow)');
9168
+ t0Enter.append('line').classed('line', true);
9169
+ t0Enter.append('line').classed('markers', true)
9170
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */.attr('marker-start', 'url(#measure-arrow-t0)').attr('marker-end', 'url(#measure-capped-arrow-t0)');
9062
9171
  const t0Label = t0Enter.append('text').classed('label', true);
9063
9172
  t0Label.append('tspan').classed('t0 math-var', true).text('t₀');
9064
9173
  t0Label.append('tspan').classed('equals', true).text(' = ');
9065
9174
  t0Label.append('tspan').classed('value', true);
9066
9175
  // MERGE
9176
+ const t0Length = Math.abs(timeScale(0) - timeScale(this.t0));
9177
+ const t0Short = t0Length <= markerCorrection * 2;
9067
9178
  const t0Merge = t0Enter.merge(t0Update);
9068
- t0Merge.select('.line').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(0) + 2).attr('y1', evidenceScale(this.startingPoint) - this.rem * 0.75).attr('x2', timeScale(this.t0) - 2).attr('y2', evidenceScale(this.startingPoint) - this.rem * 0.75);
9179
+ t0Merge.select('.line').classed('short', t0Short).transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(0) + markerCorrection).attr('y1', evidenceScale(this.startingPoint) - this.rem * 0.75).attr('x2', timeScale(this.t0) - markerCorrection).attr('y2', evidenceScale(this.startingPoint) - this.rem * 0.75);
9180
+ t0Merge.select('.markers').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', timeScale(0)).attr('y1', evidenceScale(this.startingPoint) - this.rem * 0.75).attr('x2', timeScale(this.t0)).attr('y2', evidenceScale(this.startingPoint) - this.rem * 0.75);
9069
9181
  const t0LabelMerge = t0Merge.select('.label').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x', timeScale(this.t0) + this.rem * 0.25).attr('y', evidenceScale(this.bounds.upper) - this.rem * 0.25);
9070
9182
  t0LabelMerge.select('.value').text(format('d')(this.t0));
9071
9183
  // EXIT
@@ -9134,7 +9246,12 @@
9134
9246
  const sdEnter = sdUpdate.enter().append('g').attr('class', datum => {
9135
9247
  return `model sd ${datum.outcome}`;
9136
9248
  });
9137
- sdEnter.append('line').classed('indicator', true).attr('marker-start', 'url(#model-sd-cap)').attr('marker-end', 'url(#model-sd-cap)');
9249
+ sdEnter.append('line').classed('indicator', true)
9250
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */.attr('marker-start', datum => {
9251
+ return `url(#model-sd-cap-${datum.outcome})`;
9252
+ }).attr('marker-end', datum => {
9253
+ return `url(#model-sd-cap-${datum.outcome})`;
9254
+ });
9138
9255
  // MERGE
9139
9256
  const sdMerge = sdEnter.merge(sdUpdate);
9140
9257
  sdMerge.select('.indicator').transition().duration(this.drag ? 0 : transitionDuration).ease(cubicOut).attr('x1', datum => {
@@ -9158,7 +9275,12 @@
9158
9275
  const dataSDEnter = dataSDUpdate.enter().append('g').attr('class', datum => {
9159
9276
  return `data sd ${datum.outcome}`;
9160
9277
  });
9161
- dataSDEnter.append('line').classed('indicator', true).attr('marker-start', 'url(#data-sd-cap)').attr('marker-end', 'url(#data-sd-cap)').attr('y1', datum => {
9278
+ dataSDEnter.append('line').classed('indicator', true)
9279
+ /* Hack to avoid lack of context-stroke and context-fill in Safari */.attr('marker-start', datum => {
9280
+ return `url(#data-sd-cap-${datum.outcome})`;
9281
+ }).attr('marker-end', datum => {
9282
+ return `url(#data-sd-cap-${datum.outcome})`;
9283
+ }).attr('y1', datum => {
9162
9284
  return datum.densityScale(0) + (datum.outcome === 'correct' ? 0.375 : -0.375) * this.rem;
9163
9285
  }).attr('y2', datum => {
9164
9286
  return datum.densityScale(0) + (datum.outcome === 'correct' ? 0.375 : -0.375) * this.rem;