Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Adjust piechart viewbox for mobile devices with small width #4288

Merged
merged 12 commits into from
Nov 28, 2023
4 changes: 2 additions & 2 deletions cypress/integration/rendering/pie.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
});
});

Expand All @@ -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');
});
});
Expand Down
35 changes: 19 additions & 16 deletions packages/mermaid/src/diagrams/pie/pieRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type d3 from 'd3';
import { scaleOrdinal, pie as d3pie, arc } from 'd3';

import { log } from '../../logger.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import { getConfig } from '../../diagram-api/diagramAPI.js';
Expand Down Expand Up @@ -38,33 +37,25 @@ const createPieArcs = (sections: Sections): d3.PieArcDatum<D3Sections>[] => {
*/
export const draw: DrawDefinition = (text, id, _version, diagObj) => {
log.debug('rendering pie chart\n' + text);

const db = diagObj.db as PieDB;
const globalConfig: MermaidConfig = getConfig();
const pieConfig: Required<PieDiagramConfig> = cleanAndMerge(db.getConfig(), globalConfig.pie);

const height = 450;
// TODO: remove document width
const width: number =
document.getElementById(id)?.parentElement?.offsetWidth ?? pieConfig.useWidth;
const svg: SVG = selectSvgElement(id);
// Set viewBox
svg.attr('viewBox', `0 0 ${width} ${height}`);
configureSvgSize(svg, height, width, pieConfig.useMaxWidth);

const MARGIN = 40;
const LEGEND_RECT_SIZE = 18;
const LEGEND_SPACING = 4;

const height = 450;
const pieWidth: number = height;
const svg: SVG = selectSvgElement(id);
const group: Group = svg.append('g');
group.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
const sections: Sections = db.getSections();
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<unknown, d3.PieArcDatum<D3Sections>> = arc<
d3.PieArcDatum<D3Sections>
Expand All @@ -84,7 +75,6 @@ export const draw: DrawDefinition = (text, id, _version, diagObj) => {
.attr('r', radius + outerStrokeWidth / 2)
.attr('class', 'pieOuterCircle');

const sections: Sections = db.getSections();
const arcs: d3.PieArcDatum<D3Sections>[] = createPieArcs(sections);

const myGeneratedColors = [
Expand Down Expand Up @@ -177,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 };
14 changes: 1 addition & 13 deletions packages/mermaid/src/setupGraphViewbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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}`;
Expand Down