import { HTMLWidget, publish, Utility } from "@hpcc-js/common";
import { select as d3Select } from "d3-selection";
import { bullet as d3Bullet } from "d3v4-bullet";
import "../src/Bullet.css";
export class Bullet extends HTMLWidget {
@publish(null, "set", "Title Column", function () { return this.columns(); }, { optional: true })
titleColumn: publish;
@publish(null, "set", "Subtitle Column", function () { return this.columns(); }, { optional: true })
subtitleColumn: publish;
@publish(null, "set", "Ranges Column", function () { return this.columns(); }, { optional: true })
rangesColumn: publish;
@publish(null, "set", "Measures Column", function () { return this.columns(); }, { optional: true })
measuresColumn: publish;
@publish(null, "set", "Markers Column", function () { return this.columns(); }, { optional: true })
markersColumn: publish;
private _hiddenColumns = {};
constructor() {
super();
Utility.SimpleSelectionMixin.call(this, true);
}
bulletData() {
const context = this;
this._hiddenColumns = {};
const columns = this.columns();
return this.data().map(function (row) {
return {
title: valueOf(row, this.titleColumn()),
subtitle: valueOf(row, this.subtitleColumn()),
ranges: valueOf(row, this.rangesColumn(), "range"),
measures: valueOf(row, this.measuresColumn(), "measure"),
markers: valueOf(row, this.markersColumn(), "marker"),
origRow: row
};
}, this);
function valueOf(row, column, columnType?) {
const colIdx = columns.indexOf(column);
if (colIdx >= 0) {
if (row[colIdx] instanceof Array) {
return row[colIdx];
}
return [row[colIdx]];
}
if (columnType) {
context._hiddenColumns[columnType] = true;
}
return [0];
}
}
enter(domNode, element) {
super.enter(domNode, element);
d3Select(domNode.parentNode).style("overflow", "auto");
this._selection.widgetElement(element);
}
update(_domNode, element) {
super.update(_domNode, element);
const context = this;
element.selectAll(".axis")
.style("display", "none")
;
element.selectAll(".range,.measure,.marker")
.style("display", null)
;
const margin = { left: 2, top: 8, right: 2, bottom: 8 };
const width = this.width() - margin.left - margin.right;
const height = 40 - margin.top - margin.bottom;
const svg = element.selectAll("svg").data(this.bulletData());
const svgUpdate = svg.enter().append("svg")
.attr("class", "bullet")
.call(this._selection.enter.bind(this._selection))
.on("click", function (d) {
context.click(context.rowToObj(d.origRow), context.titleColumn(), context._selection.selected(this));
})
.on("dblclick", function (d) {
context.dblclick(context.rowToObj(d.origRow), context.titleColumn(), context._selection.selected(this));
})
.each(function () {
const element2 = d3Select(this);
const bulletBar = element2.append("g")
.attr("class", (d, i) => "bulletBar series series-" + context.cssTag(context.titleColumn()))
;
const bulletTitle = bulletBar.append("g")
.attr("class", "bulletTitle")
;
bulletTitle.append("text")
.attr("class", "title")
;
bulletTitle.append("text")
.attr("class", "subtitle")
.attr("dy", "1em")
;
})
.merge(svg)
;
// Title ---
const title = svgUpdate.select(".bulletTitle")
.style("text-anchor", "end")
.attr("transform", "translate(-6," + height / 2 + ")")
;
title.select(".title")
.text(function (d) { return d.title; })
;
title.select(".subtitle")
.text(function (d) { return d.subtitle; })
;
let titleWidth = 0;
title.each(function () {
const bbox = this.getBBox();
if (bbox.width > titleWidth) {
titleWidth = bbox.width;
}
});
titleWidth; // Gap between title and bullet bar.
// Bullet Chart ---
const chart = d3Bullet()
.width(width - titleWidth - 6)
.height(height)
;
svgUpdate
.attr("width", width)
.attr("height", height + margin.top + margin.bottom)
.style("margin-left", `${margin.left}px`)
;
svgUpdate.select(".bulletBar")
.attr("transform", "translate(" + (titleWidth + 6) + "," + margin.top + ")")
.call(chart)
;
svg.exit().remove();
if (Object.keys(this._hiddenColumns).length > 0) {
element.selectAll(`.${Object.keys(this._hiddenColumns).join(",.")}`)
.style("display", "none")
;
}
}
exit(domNode, element) {
super.exit(domNode, element);
}
// Events ---
click(row, column, selected) {
console.log("Click: " + JSON.stringify(row) + ", " + column + "," + selected);
}
dblclick(row, column, selected) {
console.log("Double click: " + JSON.stringify(row) + ", " + column + "," + selected);
}
// SimpleSelectionMixin
_selection;
}
Bullet.prototype._class += " chart_Bullet";