import {interpolateHslLong as d3InterpolateHslLong} from "d3-interpolate";import {hsl as d3Hsl} from "d3-color";import {scaleSequentialLog as d3ScaleSequentialLog} from "d3-scale";import {$TOOLTIP} from "../../config/classes";import {loadConfig} from "../../config/config";import Plugin from "../Plugin";import Options from "./Options";import Elements from "./Elements";import ColorScale from "./ColorScale";import {compareEpochs, isEmpty, isFunction, isString, parseDate, pointInRegion} from "./util";
export default class Stanford extends Plugin { private config; private colorScale; private elements;
constructor(options) { super(options); this.config = new Options();
return this; }
$beforeInit(): void { const {$$} = this;
$$.config.data_xSort = false; $$.isMultipleX = () => true; $$.showGridFocus = () => {}; $$.labelishData = d => d.values; $$.opacityForCircle = () => 1;
const getCurrentPaddingRight = $$.getCurrentPaddingRight.bind($$);
$$.getCurrentPaddingRight = () => ( getCurrentPaddingRight() + ( this.colorScale ? this.colorScale.getColorScalePadding() : 0 ) ); }
$init(): void { const {$$} = this;
loadConfig.call(this, this.options); $$.color = this.getStanfordPointColor.bind($$);
this.colorScale = new ColorScale(this); this.elements = new Elements(this);
this.convertData(); this.initStanfordData(); this.setStanfordTooltip(); this.colorScale.drawColorScale();
this.$redraw(); }
$redraw(duration?: number): void { this.colorScale?.drawColorScale(); this.elements?.updateStanfordElements(duration); }
getOptions(): Options { return new Options(); }
convertData(): void { const data = this.$$.data.targets; const epochs = this.options.epochs;
data.forEach(d => { d.values.forEach((v, i) => { v.epochs = epochs[i]; });
d.minEpochs = undefined; d.maxEpochs = undefined; d.colors = undefined; d.colorscale = undefined; }); }
xvCustom(d, xyValue): number { const $$ = this; const {axis, config} = $$; let value = xyValue ? d[xyValue] : $$.getBaseValue(d);
if (axis.isTimeSeries()) { value = parseDate.call($$, value); } else if (axis.isCategorized() && isString(value)) { value = config.axis_x_categories.indexOf(d.value); }
return Math.ceil($$.scale.x(value)); }
yvCustom(d, xyValue): number { const $$ = this; const {scale} = $$; const yScale = d.axis && d.axis === "y2" ? scale.y2 : scale.y; const value = xyValue ? d[xyValue] : $$.getBaseValue(d);
return Math.ceil(yScale(value)); }
initStanfordData(): void { const {config} = this; const target = this.$$.data.targets[0];
target.values.sort(compareEpochs);
const epochs = target.values.map(a => a.epochs);
target.minEpochs = !isNaN(config.scale_min) ? config.scale_min : Math.min(...epochs); target.maxEpochs = !isNaN(config.scale_max) ? config.scale_max : Math.max(...epochs);
target.colors = isFunction(config.colors) ? config.colors : d3InterpolateHslLong(d3Hsl(250, 1, 0.5), d3Hsl(0, 1, 0.5));
target.colorscale = d3ScaleSequentialLog(target.colors) .domain([target.minEpochs, target.maxEpochs]); }
getStanfordPointColor(d) { const target = this.data.targets[0];
return target.colorscale(d.epochs); }
setStanfordTooltip(): string | undefined { const {config} = this.$$;
if (isEmpty(config.tooltip_contents)) { config.tooltip_contents = function(d, defaultTitleFormat, defaultValueFormat, color) { let html = `<table class="${$TOOLTIP.tooltip}"><tbody>`;
d.forEach(v => { html += `<tr> <th>${defaultTitleFormat(config.data_x)}</th> <th class="value">${defaultValueFormat(v.x)}</th> </tr> <tr> <th>${defaultTitleFormat(v.id)}</th> <th class="value">${defaultValueFormat(v.value)}</th> </tr> <tr class="${$TOOLTIP.tooltipName}-${v.id}"> <td class="name"><span style="background-color:${color(v)}"></span>${defaultTitleFormat("Epochs")}</td> <td class="value">${defaultValueFormat(v.epochs)}</td> </tr>`; });
return `${html}</tbody></table>`; }; } }
countEpochsInRegion(region): {value: number, percentage: number} { const $$ = this; const target = $$.data.targets[0];
const total = target.values.reduce((accumulator, currentValue) => accumulator + Number(currentValue.epochs), 0);
const value = target.values.reduce((accumulator, currentValue) => { if (pointInRegion(currentValue, region)) { return accumulator + Number(currentValue.epochs); }
return accumulator; }, 0);
return { value, percentage: value !== 0 ? +(value / total * 100).toFixed(1) : 0 }; }}