export default function initGraph(options) { const { el, width, height, margin, thickness, fontSize, triangleSize } = getConfig(options); const svg = d3.select(el).append('svg') .attr('width', width).attr('height', height + margin); let value = options.value; let ticks = options.ticks; const { valuePath, maxPath } = addArcValue(svg, width, margin, thickness, options.value); const bottomLine = addBottomLine(svg, width, height); let tooltip = addTooltip(); addTicks(svg, triangleSize, tooltip, width, height, margin, ticks); const { valueLabel, titleLabel, subtitleLabel } = addLabels(svg, options, width, height, fontSize); return { updateTitle(text) { titleLabel.text(text); }, updateSubTitle(text) { subtitleLabel.text(text); }, updateValue(text) { text = text ? `${text}%` : ''; valueLabel.text(text); if (text) { value = parseInt(text, 10); const r = calcR(width, margin); valuePath.attr('d', createArc(-90, value, r, thickness)); } }, updateTicks(t) { ticks = t; repaintTicks(svg, triangleSize, tooltip, width, height, margin, ticks); }, fit() { fit(svg, el, value, ticks, tooltip, bottomLine, valuePath, maxPath, valueLabel, titleLabel, subtitleLabel); }, }; } function fit(svg, el, value, ticks, tooltip, bottomLine, valuePath, maxPath, valueLabel, titleLabel, subtitleLabel) { const { width, height, margin, thickness, fontSize, triangleSize } = getConfig({ el }); svg.attr('width', width).attr('height', height + margin); repaintBottomLine(width, height, bottomLine); repaintArc(width, margin, value, thickness, valuePath, maxPath); repaintLabels(valueLabel, titleLabel, subtitleLabel, width, height, fontSize); repaintTicks(svg, triangleSize, tooltip, width, height, margin, ticks); } function repaintTicks(svg, triangleSize, tooltip, width, height, margin, ticks) { svg.selectAll('path[tick = "custom"]').remove(); addTicks(svg, triangleSize, tooltip, width, height, margin, ticks); } function repaintBottomLine(width, height, bottomLine) { const lineFunction = d3.svg.line() .x(function (d) { return d.x; }) .y(function (d) { return d.y; }) .interpolate("linear"); bottomLine.attr("d", lineFunction([{ "x": 0, "y": height }, { "x": width, "y": height }])) .attr("stroke-width", width / 80); } function repaintArc(width, margin, value, thickness, valuePath, maxPath) { const r = calcR(width, margin); valuePath.attr('d', createArc(-90, value, r, thickness)) .attr('transform', 'translate(' + (margin + r) + ',' + (margin + r) + '), scale(1, 1)'); maxPath.attr('d', createArc(-90, 100, r, thickness)) .attr('transform', 'translate(' + (margin + r) + ',' + (margin + r) + '), scale(1, 1)'); } function repaintLabels(valueLabel, titleLabel, subtitleLabel, width, height, fontSize) { valueLabel.attr("x", width / 2) .attr("y", height / 4 + fontSize / 1.2) .attr("dy", fontSize / 2) .style("font-size", fontSize + "px"); titleLabel.attr("x", width / 2) .attr("y", height / 4 + 2 * fontSize) .attr("dy", fontSize / 4) .style("font-size", fontSize / 1.5 + "px"); subtitleLabel.attr("x", width / 2) .attr("y", height / 4 + 3 * fontSize) .attr("dy", fontSize / 4) .style("font-size", fontSize / 2 + "px") .style("letter-spacing", `${fontSize / 18}px`); } function addTooltip() { let tooltip = d3.select('#percent-gauge-tooltip'); if (tooltip.empty()) { tooltip = d3.select("body").append("div") .attr('class', 'hover-label') .attr("class", "percent-gauge-tooltip") .attr("id", "percent-gauge-tooltip") .style("opacity", 0); } return tooltip; } function addArcValue(svg, width, margin, thickness, value) { const valuePath = addArc(svg, width, margin, thickness, 'gauge-value-path', value); const maxPath = addArc(svg, width, margin, thickness, 'none', 100); return { valuePath, maxPath, }; } function addLabels(svg, options, width, height, fontSize) { return { valueLabel: addText(options.value ? `${options.value}%` : '0%', svg, width / 2, height / 4 + fontSize / 1.2, fontSize), titleLabel: addText(options.title, svg, width / 2, height / 4 + 2 * fontSize, fontSize / 1.5), subtitleLabel: addText(options.subtitle, svg, width / 2, height / 4 + 3 * fontSize, fontSize / 2, fontSize / 18, 1.5), } } function addBottomLine(svg, width, height) { const lineFunction = d3.svg.line() .x(function (d) { return d.x; }) .y(function (d) { return d.y; }) .interpolate("linear"); return svg.append("path") .attr("d", lineFunction([{ "x": 0, "y": height }, { "x": width, "y": height }])) .attr("class", "gauge-text-stroke") .attr("stroke-width", width / 80) .attr("fill", "none"); } function addTicks(svg, triangleSize, tooltip, width, height, margin, ticks) { (ticks || []).forEach(tick => { if (tick.value !==0 && !tick.value) { return } const value = parseInt(tick.value, 10); const p1 = valueToPoint(width, height, margin, value, 1.1) const p2 = valueToPoint(width, height, margin, value, 0.88) const p3 = { x: p1.x - triangleSize * sin(value), y: p1.y + triangleSize * cos(value) } const p4 = { x: p1.x + triangleSize * sin(value), y: p1.y - triangleSize * cos(value) } let tr = ''; tick.labels.forEach(label => { tr += `
| ${window.l('service:intl').t('clusterDashboard.node')} | ${window.l('service:intl').t('clusterDashboard.value')} |
|---|