From 77999f0b37c02def3deebcb46e94f243924c30b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Issue=E5=93=A5?= Date: Mon, 10 Apr 2023 18:24:53 +0800 Subject: [PATCH 1/8] fix: adjust piechart viewbox for mobile devices with small width --- .../mermaid/src/diagrams/pie/pieRenderer.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/mermaid/src/diagrams/pie/pieRenderer.js b/packages/mermaid/src/diagrams/pie/pieRenderer.js index 1ee34e192a..5c420d3311 100644 --- a/packages/mermaid/src/diagrams/pie/pieRenderer.js +++ b/packages/mermaid/src/diagrams/pie/pieRenderer.js @@ -6,6 +6,12 @@ import * as configApi from '../../config.js'; import { parseFontSize } from '../../utils.js'; let conf = configApi.getConfig(); +// https://stackoverflow.com/a/35373030/3469145 +const getTextWidth = (function () { + const canvas = document.createElement('canvas') + const context = canvas.getContext('2d') + return text => context.measureText(text).width * window.devicePixelRatio +})(); /** * Draws a Pie Chart with the data given in text. @@ -73,6 +79,18 @@ export const draw = (txt, id, _version, diagObj) => { sum += data[key]; }); + const legendShowData = diagObj.db.getShowData() || conf.showData || conf.pie.showData; + const legendTexts = Object.keys(data).map(key => { + if (!legendShowData) { + return key; + } + return key + ' [' + data[key] + ']'; + }) + const legendTextWidths = legendTexts.map(v => getTextWidth(v)).sort((a, b) => a - b); + const longestTextWidth = parseInt(legendTextWidths.pop()); + const newWidth = width + margin + legendRectSize + legendSpacing + longestTextWidth; + elem.setAttribute("viewBox", "0 0 " + newWidth + " " + height); + const themeVariables = conf.themeVariables; var myGeneratedColors = [ themeVariables.pie1, From f211ed686c6deb63481cf3a2a57850fa00ab4fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Issue=E5=93=A5?= Date: Tue, 27 Jun 2023 21:56:38 +0800 Subject: [PATCH 2/8] fix: apply suggested changes for PR #4288 --- packages/mermaid/src/diagrams/pie/pieRenderer.js | 14 ++++---------- .../mermaid/src/rendering-util/getTextWidth.js | 7 +++++++ 2 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 packages/mermaid/src/rendering-util/getTextWidth.js diff --git a/packages/mermaid/src/diagrams/pie/pieRenderer.js b/packages/mermaid/src/diagrams/pie/pieRenderer.js index 5c420d3311..06ed541749 100644 --- a/packages/mermaid/src/diagrams/pie/pieRenderer.js +++ b/packages/mermaid/src/diagrams/pie/pieRenderer.js @@ -4,14 +4,9 @@ import { log } from '../../logger.js'; import { configureSvgSize } from '../../setupGraphViewbox.js'; import * as configApi from '../../config.js'; import { parseFontSize } from '../../utils.js'; +import { getTextWidth } from '../../rendering-util/getTextWidth.js'; let conf = configApi.getConfig(); -// https://stackoverflow.com/a/35373030/3469145 -const getTextWidth = (function () { - const canvas = document.createElement('canvas') - const context = canvas.getContext('2d') - return text => context.measureText(text).width * window.devicePixelRatio -})(); /** * Draws a Pie Chart with the data given in text. @@ -79,15 +74,14 @@ export const draw = (txt, id, _version, diagObj) => { sum += data[key]; }); - const legendShowData = diagObj.db.getShowData() || conf.showData || conf.pie.showData; + const legendShowData = diagObj.db.getShowData() || conf.showData || conf.pie.showData || false; const legendTexts = Object.keys(data).map(key => { if (!legendShowData) { return key; } - return key + ' [' + data[key] + ']'; + return `${key} [${data[key]}]`; }) - const legendTextWidths = legendTexts.map(v => getTextWidth(v)).sort((a, b) => a - b); - const longestTextWidth = parseInt(legendTextWidths.pop()); + const longestTextWidth = Math.max(...(legendTexts.map(v => getTextWidth(v)))); const newWidth = width + margin + legendRectSize + legendSpacing + longestTextWidth; elem.setAttribute("viewBox", "0 0 " + newWidth + " " + height); diff --git a/packages/mermaid/src/rendering-util/getTextWidth.js b/packages/mermaid/src/rendering-util/getTextWidth.js new file mode 100644 index 0000000000..f2976a852a --- /dev/null +++ b/packages/mermaid/src/rendering-util/getTextWidth.js @@ -0,0 +1,7 @@ +// https://stackoverflow.com/a/35373030/3469145 +const canvas = document.createElement('canvas'); +const context = canvas.getContext('2d'); + +const getTextWidth = (text) => context.measureText(text).width * window.devicePixelRatio; + +export { getTextWidth }; From a2d1fb5e5468fcb5a51ba081ea90ee999889d60d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Issue=E5=93=A5?= Date: Fri, 7 Jul 2023 15:42:40 +0800 Subject: [PATCH 3/8] use computeWidthOfText --- packages/mermaid/src/diagrams/pie/pieRenderer.js | 10 ++++++---- packages/mermaid/src/rendering-util/createText.js | 2 +- packages/mermaid/src/rendering-util/getTextWidth.js | 7 ------- 3 files changed, 7 insertions(+), 12 deletions(-) delete mode 100644 packages/mermaid/src/rendering-util/getTextWidth.js diff --git a/packages/mermaid/src/diagrams/pie/pieRenderer.js b/packages/mermaid/src/diagrams/pie/pieRenderer.js index 06ed541749..0a36af3c57 100644 --- a/packages/mermaid/src/diagrams/pie/pieRenderer.js +++ b/packages/mermaid/src/diagrams/pie/pieRenderer.js @@ -4,7 +4,7 @@ import { log } from '../../logger.js'; import { configureSvgSize } from '../../setupGraphViewbox.js'; import * as configApi from '../../config.js'; import { parseFontSize } from '../../utils.js'; -import { getTextWidth } from '../../rendering-util/getTextWidth.js'; +import { computeWidthOfText } from '../../rendering-util/createText.js'; let conf = configApi.getConfig(); @@ -74,16 +74,18 @@ export const draw = (txt, id, _version, diagObj) => { sum += data[key]; }); - const legendShowData = diagObj.db.getShowData() || conf.showData || conf.pie.showData || false; + const legendShowData = diagObj.db.getShowData(); const legendTexts = Object.keys(data).map(key => { if (!legendShowData) { return key; } return `${key} [${data[key]}]`; }) - const longestTextWidth = Math.max(...(legendTexts.map(v => getTextWidth(v)))); + const longestTextWidth = Math.max(...(legendTexts.map(text => { + return computeWidthOfText(svg, 1, text) + }))); const newWidth = width + margin + legendRectSize + legendSpacing + longestTextWidth; - elem.setAttribute("viewBox", "0 0 " + newWidth + " " + height); + elem.setAttribute("viewBox", `0 0 ${newWidth} ${height}`); const themeVariables = conf.themeVariables; var myGeneratedColors = [ diff --git a/packages/mermaid/src/rendering-util/createText.js b/packages/mermaid/src/rendering-util/createText.js index 871f3425e2..25a7b0c1a5 100644 --- a/packages/mermaid/src/rendering-util/createText.js +++ b/packages/mermaid/src/rendering-util/createText.js @@ -85,7 +85,7 @@ function createTspan(textElement, lineIndex, lineHeight) { * @param {string} text * @returns {number} */ -function computeWidthOfText(parentNode, lineHeight, text) { +export function computeWidthOfText(parentNode, lineHeight, text) { const testElement = parentNode.append('text'); const testSpan = createTspan(testElement, 1, lineHeight); updateTextContentAndStyles(testSpan, [{ content: text, type: 'normal' }]); diff --git a/packages/mermaid/src/rendering-util/getTextWidth.js b/packages/mermaid/src/rendering-util/getTextWidth.js deleted file mode 100644 index f2976a852a..0000000000 --- a/packages/mermaid/src/rendering-util/getTextWidth.js +++ /dev/null @@ -1,7 +0,0 @@ -// https://stackoverflow.com/a/35373030/3469145 -const canvas = document.createElement('canvas'); -const context = canvas.getContext('2d'); - -const getTextWidth = (text) => context.measureText(text).width * window.devicePixelRatio; - -export { getTextWidth }; From 0620c6daf2249ff311324831f82e75408638ee57 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 28 Nov 2023 10:34:58 +0530 Subject: [PATCH 4/8] chore: Cleanup setupGraphViewbox --- packages/mermaid/src/setupGraphViewbox.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/mermaid/src/setupGraphViewbox.js b/packages/mermaid/src/setupGraphViewbox.js index ba74b79fdd..d3df6db7cf 100644 --- a/packages/mermaid/src/setupGraphViewbox.js +++ b/packages/mermaid/src/setupGraphViewbox.js @@ -44,6 +44,7 @@ export const configureSvgSize = function (svgElem, height, width, useMaxWidth) { const attrs = calculateSvgSizeAttrs(height, width, useMaxWidth); d3Attrs(svgElem, attrs); }; + export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) { const svgBounds = svgElem.node().getBBox(); const sWidth = svgBounds.width; @@ -55,26 +56,13 @@ export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) let height = 0; log.info(`Graph bounds: ${width}x${height}`, graph); - // let tx = 0; - // let ty = 0; - // if (sWidth > width) { - // tx = (sWidth - width) / 2 + padding; width = sWidth + padding * 2; - // } else { - // if (Math.abs(sWidth - width) >= 2 * padding + 1) { - // width = width - padding; - // } - // } - // if (sHeight > height) { - // ty = (sHeight - height) / 2 + padding; height = sHeight + padding * 2; - // } log.info(`Calculated bounds: ${width}x${height}`); configureSvgSize(svgElem, height, width, useMaxWidth); // Ensure the viewBox includes the whole svgBounds area with extra space for padding - // const vBox = `0 0 ${width} ${height}`; const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${ svgBounds.width + 2 * padding } ${svgBounds.height + 2 * padding}`; From 403ac4b76b8c47a6d9493210d7d95fd5c8a62341 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 28 Nov 2023 10:39:34 +0530 Subject: [PATCH 5/8] chore: Fix computeWidth function --- packages/mermaid/src/diagrams/pie/pieRenderer.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mermaid/src/diagrams/pie/pieRenderer.ts b/packages/mermaid/src/diagrams/pie/pieRenderer.ts index c7f191e723..2d10cd33d5 100644 --- a/packages/mermaid/src/diagrams/pie/pieRenderer.ts +++ b/packages/mermaid/src/diagrams/pie/pieRenderer.ts @@ -8,7 +8,7 @@ import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js'; import type { D3Sections, PieDB, Sections } from './pieTypes.js'; import type { MermaidConfig, PieDiagramConfig } from '../../config.type.js'; import { selectSvgElement } from '../../rendering-util/selectSvgElement.js'; -import { computeWidthOfText } from '../../rendering-util/createText.js'; +import { computeDimensionOfText } from '../../rendering-util/createText.js'; const createPieArcs = (sections: Sections): d3.PieArcDatum[] => { // Compute the position of each group on the pie: @@ -48,6 +48,7 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { const width: number = document.getElementById(id)?.parentElement?.offsetWidth ?? pieConfig.useWidth; const svg: SVG = selectSvgElement(id); + const group: Group = svg.append('g'); const sections: Sections = db.getSections(); const legendShowData = db.getShowData(); const legendTexts = Object.keys(sections).map((key) => { @@ -58,7 +59,7 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { }); const longestTextWidth = Math.max( ...legendTexts.map((text) => { - return computeWidthOfText(svg, 1, text); + return computeDimensionOfText(group, 1, text)?.width ?? 0; }) ); const newWidth = width + MARGIN + LEGEND_RECT_SIZE + LEGEND_SPACING + longestTextWidth; @@ -67,7 +68,6 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { svg.attr('viewBox', `0 0 ${newWidth} ${height}`); configureSvgSize(svg, height, newWidth, pieConfig.useMaxWidth); - const group: Group = svg.append('g'); group.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); const { themeVariables } = globalConfig; From 9c2dae92f83bbc7ffe50c6cef76d415f1ac1bf92 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 28 Nov 2023 11:30:41 +0530 Subject: [PATCH 6/8] refactor: Remove unnecessary calculations --- .../mermaid/src/diagrams/pie/pieRenderer.ts | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/mermaid/src/diagrams/pie/pieRenderer.ts b/packages/mermaid/src/diagrams/pie/pieRenderer.ts index 2d10cd33d5..a24bcb532b 100644 --- a/packages/mermaid/src/diagrams/pie/pieRenderer.ts +++ b/packages/mermaid/src/diagrams/pie/pieRenderer.ts @@ -8,7 +8,6 @@ import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js'; import type { D3Sections, PieDB, Sections } from './pieTypes.js'; import type { MermaidConfig, PieDiagramConfig } from '../../config.type.js'; import { selectSvgElement } from '../../rendering-util/selectSvgElement.js'; -import { computeDimensionOfText } from '../../rendering-util/createText.js'; const createPieArcs = (sections: Sections): d3.PieArcDatum[] => { // Compute the position of each group on the pie: @@ -45,37 +44,18 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { const LEGEND_RECT_SIZE = 18; const LEGEND_SPACING = 4; const height = 450; - const width: number = - document.getElementById(id)?.parentElement?.offsetWidth ?? pieConfig.useWidth; + const pieWidth: number = height; const svg: SVG = selectSvgElement(id); const group: Group = svg.append('g'); const sections: Sections = db.getSections(); - const legendShowData = db.getShowData(); - const legendTexts = Object.keys(sections).map((key) => { - if (!legendShowData) { - return key; - } - return `${key} [${sections[key]}]`; - }); - const longestTextWidth = Math.max( - ...legendTexts.map((text) => { - return computeDimensionOfText(group, 1, text)?.width ?? 0; - }) - ); - const newWidth = width + MARGIN + LEGEND_RECT_SIZE + LEGEND_SPACING + longestTextWidth; - - // Set viewBox - svg.attr('viewBox', `0 0 ${newWidth} ${height}`); - configureSvgSize(svg, height, newWidth, pieConfig.useMaxWidth); - - group.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); + group.attr('transform', 'translate(' + pieWidth / 2 + ',' + height / 2 + ')'); const { themeVariables } = globalConfig; let [outerStrokeWidth] = parseFontSize(themeVariables.pieOuterStrokeWidth); outerStrokeWidth ??= 2; const textPosition: number = pieConfig.textPosition; - const radius: number = Math.min(width, height) / 2 - MARGIN; + const radius: number = Math.min(pieWidth, height) / 2 - MARGIN; // Shape helper to build arcs: const arcGenerator: d3.Arc> = arc< d3.PieArcDatum @@ -187,6 +167,19 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => { } return label; }); + + const longestTextWidth = Math.max( + ...legend + .selectAll('text') + .nodes() + .map((node) => (node as Element)?.getBoundingClientRect().width ?? 0) + ); + + const totalWidth = pieWidth + MARGIN + LEGEND_RECT_SIZE + LEGEND_SPACING + longestTextWidth; + + // Set viewBox + svg.attr('viewBox', `0 0 ${totalWidth} ${height}`); + configureSvgSize(svg, height, totalWidth, pieConfig.useMaxWidth); }; export const renderer = { draw }; From 89b392327afc87caa0360f310b77f23b4bdf92b5 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 28 Nov 2023 11:34:58 +0530 Subject: [PATCH 7/8] chore: Revert unnecessary export --- packages/mermaid/src/rendering-util/createText.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/mermaid/src/rendering-util/createText.ts b/packages/mermaid/src/rendering-util/createText.ts index 06697bc7d7..2b48cf5f3a 100644 --- a/packages/mermaid/src/rendering-util/createText.ts +++ b/packages/mermaid/src/rendering-util/createText.ts @@ -69,11 +69,7 @@ function createTspan(textElement: any, lineIndex: number, lineHeight: number) { .attr('dy', lineHeight + 'em'); } -export function computeWidthOfText( - parentNode: any, - lineHeight: number, - line: MarkdownLine -): number { +function computeWidthOfText(parentNode: any, lineHeight: number, line: MarkdownLine): number { const testElement = parentNode.append('text'); const testSpan = createTspan(testElement, 1, lineHeight); updateTextContentAndStyles(testSpan, line); From 005c9984383068f2ea19f82557ebf11086d5e4f5 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Tue, 28 Nov 2023 11:37:12 +0000 Subject: [PATCH 8/8] test(e2e): fix pie chart E2E tests for PR #4288 --- cypress/integration/rendering/pie.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/integration/rendering/pie.spec.ts b/cypress/integration/rendering/pie.spec.ts index 269efafb26..4a1d774c0a 100644 --- a/cypress/integration/rendering/pie.spec.ts +++ b/cypress/integration/rendering/pie.spec.ts @@ -44,7 +44,7 @@ describe('pie chart', () => { const style = svg.attr('style'); expect(style).to.match(/^max-width: [\d.]+px;$/); const maxWidthValue = parseFloat(style.match(/[\d.]+/g).join('')); - expect(maxWidthValue).to.eq(984); + expect(maxWidthValue).to.be.within(590, 600); // depends on installed fonts: 596.2 on my PC, 597.5 on CI }); }); @@ -59,7 +59,7 @@ describe('pie chart', () => { ); cy.get('svg').should((svg) => { const width = parseFloat(svg.attr('width')); - expect(width).to.eq(984); + expect(width).to.be.within(590, 600); // depends on installed fonts: 596.2 on my PC, 597.5 on CI expect(svg).to.not.have.attr('style'); }); });