@allurereport/web-allure2
Version:
The static files for Allure Classic Report
203 lines (176 loc) • 5.57 kB
JavaScript
import { max } from "d3-array";
import { scaleLinear, scalePoint } from "d3-scale";
import { scaleOrdinal } from "d3-scale";
import { schemeCategory10 } from "d3-scale-chromatic";
import { area, line, stack } from "d3-shape";
import BaseChartView from "@/components/graph-base/BaseChartView.js";
import TooltipView from "@/components/tooltip/TooltipView.js";
import translate from "@/helpers/t.js";
import "./styles.scss";
import trendTooltip from "./trend-tooltip.hbs";
class TrendChartView extends BaseChartView {
PAD_BOTTOM = 50;
initialize(options) {
this.x = scalePoint();
this.y = scaleLinear();
this.tooltip = new TooltipView({ position: "top" });
this.keys = options.keys || this.model.keys();
this.stack = stack()
.keys(this.keys)
.value((d, key) => d.data[key] || 0);
this.color = options.colors || scaleOrdinal(schemeCategory10);
options.notStacked && this.stack.offset(() => {});
this.yTickFormat = options.yTickFormat || ((d) => d);
}
onAttach() {
const data = this.model.toJSON();
if (data && data.length > 1) {
this.doShow(data);
} else {
this.$el.html(`<div class="widget__noitems">${translate("chart.trend.empty")}</div>`);
}
super.onAttach();
}
doShow(data) {
this.setupViewport();
this.x.range([0, this.width]);
this.y.range([this.height, 0]);
this.x.domain(data.map((d) => d.id));
this.y.domain([0, max(data, (d) => d.total)]).nice();
const trendStack = this.stack(data);
this.makeBottomAxis({
scale: this.x,
tickFormat: (d, i) => data[i].name,
});
this.makeLeftAxis({
scale: this.y,
tickFormat: this.yTickFormat,
});
if (document.dir === "rtl") {
this.svg.selectAll(".chart__axis_x").selectAll("text").style("text-anchor", "start");
} else {
this.svg.selectAll(".chart__axis_x").selectAll("text").style("text-anchor", "end");
}
this.svg
.selectAll(".chart__axis_x")
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", "-.6em")
.attr("transform", "rotate(-90)");
this.options.hideAreas || this.showAreas(trendStack);
this.options.hideLines || this.showLines(trendStack);
this.options.hidePoints || this.showPoints(trendStack);
this.showSlices(data);
}
showAreas(trendStack) {
const trendArea = area()
.x((d) => this.x(d.data.id))
.y0((d) => this.y(d[0]))
.y1((d) => this.y(d[1]));
this.plot
.selectAll(".trend__area")
.data(trendStack)
.enter()
.append("path")
.attr("class", "trend__area")
.attr("d", trendArea)
.style("fill", (d) => this.color(d.key))
.style("opacity", 0.85);
}
showLines(trendStack) {
const trendLine = line()
.x((d) => this.x(d.data.id))
.y((d) => this.y(d[1]));
this.plot
.selectAll(".trend__line")
.data(trendStack)
.enter()
.append("path")
.attr("class", ".trend__line")
.attr("d", trendLine)
.style("stroke-width", 2)
.style("stroke", (d) => this.color(d.key));
}
showPoints(trendStack) {
const points = this.plot
.selectAll(".trend_points")
.data(trendStack)
.enter()
.append("g")
.attr("class", ".trend_point")
.style("fill", (d) => this.color(d.key));
points
.selectAll(".trend_point")
.data((d) => d)
.enter()
.append("circle")
.attr("r", 2)
.attr("cx", (d) => this.x(d.data.id))
.attr("cy", (d) => this.y(d[1]))
.attr("class", "trend_point");
}
showSlices(data) {
this.plot.selectAll(".slice").data(data).enter().append("g").attr("class", "slice");
this.plot
.selectAll(".slice")
.filter((d) => d.reportUrl)
.append("a")
.attr("class", "edge")
.filter((d) => d.reportUrl)
.attr("xlink:href", (d) => d.reportUrl);
this.plot
.selectAll(".slice")
.filter((d) => !d.reportUrl)
.append("g")
.attr("class", "edge");
this.plot
.selectAll(".edge")
.append("line")
.attr("id", (d) => d.id)
.attr("x1", (d) => this.x(d.id))
.attr("y1", (d) => this.y(d.total))
.attr("x2", (d) => this.x(d.id))
.attr("y2", this.y(0))
.attr("stroke", "white")
.attr("stroke-width", 1)
.attr("class", "report-line");
this.plot
.selectAll(".edge")
.append("rect")
.style("opacity", 0.0)
.attr("class", "report-edge")
.attr("x", (d, i) => (i > 0 ? this.x(d.id) - this.x.step() / 2 : 0))
.attr("y", 0)
.attr("height", this.height)
.attr("width", (d, i) => (i === 0 || this.x(d.id) === this.width ? this.x.step() / 2 : this.x.step()))
.on("mouseover", (event, d) => {
const anchor = this.plot
.append("circle")
.attr("class", "anchor")
.attr("cx", `${this.x(d.id)}`)
.attr("cy", `${this.y(d.total / 2)}`);
this.showTooltip(d, anchor.node());
})
.on("mouseout", () => {
this.plot.selectAll(".anchor").remove();
this.hideTooltip();
});
}
getTooltipContent(selectedData) {
const tooltipData = {
...selectedData,
data: this.keys
.map((key) => {
return {
key,
num: this.yTickFormat(selectedData.data[key]),
color: this.color(key),
};
})
.filter((item) => !!item.num)
.reverse(),
};
return trendTooltip(tooltipData);
}
}
export default TrendChartView;