Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions app/assets/javascripts/kanaui/kiddo/charts/line_chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,61 +68,55 @@
return dataset.name;
}));

// Create legend container at the top
// Create legend container to the right of the chart area
var legendContainer = svg
.append("g")
.attr("class", "chart-legend")
.attr("transform", "translate(" + (self.width - 100) + ", -25)");
.attr("transform", "translate(" + (self.width + self.margin_left + 15) + ", 10)");

// Calculate total values for legend
var legendData = datasets.map(function (dataset, index) {
var latestValue = dataset.values[dataset.values.length - 1];
var totalCount = dataset.values.length;
return {
name: dataset.name,
value: latestValue ? latestValue.y : 0,
count: totalCount,
color: self.color(dataset.name),
index: index,
};
});

// Create legend items
// Create legend items as a vertical column
var legendItems = legendContainer
.selectAll(".legend-item")
.data(legendData)
.enter()
.append("g")
.attr("class", "legend-item");

var xOffset = 0;
legendItems.each(function (d, i) {
var yOffset = 0;
legendItems.each(function (d) {
var legendItem = d3.select(this);

// Add colored circle
legendItem
.append("circle")
.attr("cx", xOffset + 6)
.attr("cy", 0)
.attr("cx", 6)
.attr("cy", yOffset)
.attr("r", 6)
.style("fill", d.color);

// Add text label
var labelText =
helper.formatSeriesName(d.name) + " (" + d.count + "): " + d3.format(",.2f")(d.value);
helper.formatSeriesName(d.name, self.reportName) + ": " + helper.formatValue(d.value);
legendItem
.append("text")
.attr("x", xOffset + 18)
.attr("y", 0)
.attr("x", 18)
.attr("y", yOffset)
.attr("dy", "0.35em")
.style("font-size", "0.875rem")
.style("font-weight", "500")
.style("fill", "#6B7280")
.text(labelText);

// Calculate width for next item
var textWidth = this.getBBox().width;
xOffset += textWidth + 40; // Add spacing between items
yOffset += 22;
});

// Render data lines
Expand Down
30 changes: 20 additions & 10 deletions app/assets/javascripts/kanaui/kiddo/charts/utils/mouse_over.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,16 @@
var infoBox = info.node().getBBox();
var infoTitleBox = infoTitle.node().getBBox();
var margin = 40;
var minWidth = Math.max(box.width, infoTitleBox.width) + margin;

info.attr("height", infoBox.height + box.height + 7);
if (infoBox.width < box.width) {
info.attr("width", box.width + margin);
infoTitleBg.attr("width", box.width + margin);
if (infoBox.width < minWidth) {
info.attr("width", minWidth);
infoTitleBg.attr("width", minWidth);

$("#mouseover_canvas #info-title").attr(
"dx",
(box.width + margin) / 2 - infoTitleBox.width / 2
minWidth / 2 - infoTitleBox.width / 2
);
}
};
Expand All @@ -81,7 +82,9 @@
});

function mousemove(event) {
var mouseX = d3.pointer(event, this)[0];
var pointer = d3.pointer(event, this);
var mouseX = pointer[0];
var mouseY = pointer[1];

$("#mouseover_canvas .chart_values").detach().remove();
$("#mouseover_canvas .chart_circles").detach().remove();
Expand Down Expand Up @@ -115,11 +118,7 @@
.attr("cy", y(d.y))
.style("fill", self.color(name));

var canvasPosition = x(x0) > self.width / 2 ? 50 : self.width / 2;

canvas.attr("transform", "translate(" + canvasPosition + ",0)");

canvas.select("#info-title").text(d.date);
canvas.select("#info-title").text(helper.formatDate(d.date));

elementsForLegend.push({ element: element, d: d });
});
Expand Down Expand Up @@ -155,6 +154,17 @@

addInfoDimensions(text);
});

// Position tooltip to follow the cursor; flip left when near the right edge.
var tooltipOffset = 15;
var tooltipWidth = info.node().getBBox().width;
var tooltipHeight = info.node().getBBox().height;
var localX = (mouseX + tooltipOffset + tooltipWidth > self.width)
? mouseX - tooltipWidth - tooltipOffset
: mouseX + tooltipOffset;
var canvasX = localX + self.margin_left;
var canvasY = Math.max(0, mouseY - 150);
canvas.attr("transform", "translate(" + canvasX + "," + canvasY + ")");
}
},
};
Expand Down
47 changes: 40 additions & 7 deletions app/assets/javascripts/kanaui/kiddo/helper.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
(function (Kiddo, d3) {
Kiddo.Helper = function () {
var formatValue = function (d) {
return d % 1 === 0 ? d3.format(",d")(d) : d3.format(",.2f")(d);
};
var formatCurrency = function (d) {
return "$" + formatValue(d);
};
var formatValue = d3.format(",.2f");

var humanizeSegment = function (segment) {
segment = String(segment || "")
Expand All @@ -30,33 +32,64 @@
.join(" ");
};

var formatSeriesName = function (name) {
var formatSeriesName = function (name, reportName) {
return String(name || "")
.split(/\s*::\s*/)
.filter(function (segment) {
// Remove numeric-only segments (tenant record id)
return !/^\d+$/.test(segment.trim());
})
.map(function (segment) {
var parts = segment.split(/\s*:\s*/);
if (parts.length > 1) {
return humanizeSegment(parts[0]) + " (" + humanizeSegment(parts.slice(1).join(": ")) + ")";
var label = (reportName && parts[0].trim().toLowerCase() === "count")
? reportName
: humanizeSegment(parts[0]);
return label + " (" + humanizeSegment(parts.slice(1).join(": ")) + ")";
}

return humanizeSegment(segment);
})
.filter(function (segment) {
return segment.length > 0;
})
.join(" / ");
.join(" : ");
};

// Extracts just the qualifier part (e.g. "EUR" from "count: EUR :: 1") for compact tooltip labels
var formatSeriesLabel = function (name) {
var segments = String(name || "")
.split(/\s*::\s*/)
.filter(function (segment) {
return !/^\d+$/.test(segment.trim());
});

if (segments.length === 0) return humanizeSegment(name);

var parts = segments[0].split(/\s*:\s*/);
if (parts.length > 1) {
return humanizeSegment(parts.slice(1).join(": "));
}
return humanizeSegment(segments[0]);
};

var parseDateFn = d3.timeParse("%Y-%m-%d");
var formatDateFn = d3.timeFormat("%b %d, %Y");
var formatDate = function (dateStr) {
var parsed = parseDateFn(dateStr);
return parsed ? formatDateFn(parsed) : dateStr;
};

return {
parseDate: d3.timeParse("%Y-%m-%d"),
parseDate: parseDateFn,
bisectDate: d3.bisector(function (d) {
return d.x;
}).left,
formatCurrency: formatCurrency,
formatValue: formatValue,
formatSeriesName: formatSeriesName,
formatDate: formatDate,
formatValueDisplay: function (name, d) {
return formatSeriesName(name) + ": " + formatValue(d.y); // Add currency boolean on backend later -- formatCurrency(d.y); }
return formatSeriesLabel(name) + ": " + formatValue(d.y);
},
};
};
Expand Down
1 change: 1 addition & 0 deletions app/assets/javascripts/kanaui/kiddo/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
raw_height: raw_height,
width: raw_width - margin_left - margin_right,
height: raw_height - margin_top - margin_bottom,
reportName: $("#chartAnchor").data("report-name") || "",
};
};
})((window.Kiddo = window.Kiddo || {}), d3);
Loading
Loading