Top languages card pie layout (#2709)

* Top languages card donut layout

* Top languages card pie layout

* renames

* dev

* docs

* dev

* dev

* animations

* dev

* handle one language
This commit is contained in:
Alexandr Garbuzov
2023-05-11 08:49:57 +02:00
committed by GitHub
parent 1f4a2c4d82
commit ff9839b73c
4 changed files with 250 additions and 6 deletions
+123 -4
View File
@@ -9,6 +9,7 @@ import {
calculateCompactLayoutHeight,
calculateNormalLayoutHeight,
calculateDonutLayoutHeight,
calculatePieLayoutHeight,
donutCenterTranslation,
trimTopLanguages,
renderTopLanguages,
@@ -40,12 +41,13 @@ const langs = {
/**
* Retrieve the language percentage from the donut chart SVG.
*
* @param {string} d The SVG path element.
* @param {number} centerX The center X coordinate of the donut chart.
* @param {number} centerY The center Y coordinate of the donut chart.
* @returns {number} The percentage of the language.
*/
const langPercentFromSvg = (d, centerX, centerY) => {
const langPercentFromDonutLayoutSvg = (d, centerX, centerY) => {
const dTmp = d
.split(" ")
.filter((x) => !isNaN(x))
@@ -58,6 +60,34 @@ const langPercentFromSvg = (d, centerX, centerY) => {
return (endAngle - startAngle) / 3.6;
};
/**
* Retrieve the language percentage from the pie chart SVG.
*
* @param {string} d The SVG path element.
* @param {number} centerX The center X coordinate of the pie chart.
* @param {number} centerY The center Y coordinate of the pie chart.
* @returns {number} The percentage of the language.
*/
const langPercentFromPieLayoutSvg = (d, centerX, centerY) => {
const dTmp = d
.split(" ")
.filter((x) => !isNaN(x))
.map((x) => parseFloat(x));
const startAngle = cartesianToPolar(
centerX,
centerY,
dTmp[2],
dTmp[3],
).angleInDegrees;
let endAngle = cartesianToPolar(
centerX,
centerY,
dTmp[9],
dTmp[10],
).angleInDegrees;
return ((endAngle - startAngle) / 360) * 100;
};
describe("Test renderTopLanguages helper functions", () => {
it("getLongestLang", () => {
const langArray = Object.values(langs);
@@ -193,6 +223,20 @@ describe("Test renderTopLanguages helper functions", () => {
expect(calculateDonutLayoutHeight(10)).toBe(375);
});
it("calculatePieLayoutHeight", () => {
expect(calculatePieLayoutHeight(0)).toBe(300);
expect(calculatePieLayoutHeight(1)).toBe(325);
expect(calculatePieLayoutHeight(2)).toBe(325);
expect(calculatePieLayoutHeight(3)).toBe(350);
expect(calculatePieLayoutHeight(4)).toBe(350);
expect(calculatePieLayoutHeight(5)).toBe(375);
expect(calculatePieLayoutHeight(6)).toBe(375);
expect(calculatePieLayoutHeight(7)).toBe(400);
expect(calculatePieLayoutHeight(8)).toBe(400);
expect(calculatePieLayoutHeight(9)).toBe(425);
expect(calculatePieLayoutHeight(10)).toBe(425);
});
it("donutCenterTranslation", () => {
expect(donutCenterTranslation(0)).toBe(-45);
expect(donutCenterTranslation(1)).toBe(-45);
@@ -466,7 +510,7 @@ describe("Test renderTopLanguages", () => {
.filter((x) => !isNaN(x))
.map((x) => parseFloat(x));
const center = { x: d[7], y: d[7] };
const HTMLLangPercent = langPercentFromSvg(
const HTMLLangPercent = langPercentFromDonutLayoutSvg(
queryAllByTestId(document.body, "lang-donut")[0].getAttribute("d"),
center.x,
center.y,
@@ -480,7 +524,7 @@ describe("Test renderTopLanguages", () => {
"size",
"40",
);
const javascriptLangPercent = langPercentFromSvg(
const javascriptLangPercent = langPercentFromDonutLayoutSvg(
queryAllByTestId(document.body, "lang-donut")[1].getAttribute("d"),
center.x,
center.y,
@@ -494,7 +538,7 @@ describe("Test renderTopLanguages", () => {
"size",
"20",
);
const cssLangPercent = langPercentFromSvg(
const cssLangPercent = langPercentFromDonutLayoutSvg(
queryAllByTestId(document.body, "lang-donut")[2].getAttribute("d"),
center.x,
center.y,
@@ -520,6 +564,81 @@ describe("Test renderTopLanguages", () => {
"circle",
);
});
it("should render with layout pie", () => {
document.body.innerHTML = renderTopLanguages(langs, { layout: "pie" });
expect(queryByTestId(document.body, "header")).toHaveTextContent(
"Most Used Languages",
);
expect(queryAllByTestId(document.body, "lang-name")[0]).toHaveTextContent(
"HTML 40.00%",
);
expect(queryAllByTestId(document.body, "lang-pie")[0]).toHaveAttribute(
"size",
"40",
);
const d = queryAllByTestId(document.body, "lang-pie")[0]
.getAttribute("d")
.split(" ")
.filter((x) => !isNaN(x))
.map((x) => parseFloat(x));
const center = { x: d[0], y: d[1] };
const HTMLLangPercent = langPercentFromPieLayoutSvg(
queryAllByTestId(document.body, "lang-pie")[0].getAttribute("d"),
center.x,
center.y,
);
expect(HTMLLangPercent).toBeCloseTo(40);
expect(queryAllByTestId(document.body, "lang-name")[1]).toHaveTextContent(
"javascript 40.00%",
);
expect(queryAllByTestId(document.body, "lang-pie")[1]).toHaveAttribute(
"size",
"40",
);
const javascriptLangPercent = langPercentFromPieLayoutSvg(
queryAllByTestId(document.body, "lang-pie")[1].getAttribute("d"),
center.x,
center.y,
);
expect(javascriptLangPercent).toBeCloseTo(40);
expect(queryAllByTestId(document.body, "lang-name")[2]).toHaveTextContent(
"css 20.00%",
);
expect(queryAllByTestId(document.body, "lang-pie")[2]).toHaveAttribute(
"size",
"20",
);
const cssLangPercent = langPercentFromPieLayoutSvg(
queryAllByTestId(document.body, "lang-pie")[2].getAttribute("d"),
center.x,
center.y,
);
expect(cssLangPercent).toBeCloseTo(20);
expect(HTMLLangPercent + javascriptLangPercent + cssLangPercent).toBe(100);
// Should render full pie (circle) if one language is 100%.
document.body.innerHTML = renderTopLanguages(
{ HTML: langs.HTML },
{ layout: "pie" },
);
expect(queryAllByTestId(document.body, "lang-name")[0]).toHaveTextContent(
"HTML 100.00%",
);
expect(queryAllByTestId(document.body, "lang-pie")[0]).toHaveAttribute(
"size",
"100",
);
expect(queryAllByTestId(document.body, "lang-pie")).toHaveLength(1);
expect(queryAllByTestId(document.body, "lang-pie")[0].tagName).toBe(
"circle",
);
});
it("should render a translated title", () => {
document.body.innerHTML = renderTopLanguages(langs, { locale: "cn" });