%
/*
Draws an SVG diagram to display an interface's inheritance chain
$0 - Interface name (defaults to the interface page the macro is called on)
Test pages
- http://localhost:3000/en-US/docs/Web/API/SVGTextPositioningElement
- http://localhost:3000/en-US/docs/Web/API/WheelEvent
- http://localhost:3000/en-US/docs/Web/API/USB/connect_event
- http://localhost:3000/en-US/docs/Web/API/SVGTSpanElement
*/
const data = web.getJSONData("InterfaceData")[0];
const href = `/${env.locale}/docs/Web/API/`;
const mainInterfaceName = $0 || env.slug.replace('Web/API/','').split('/')[0];
let height = 40;
let xpos = 0;
let ypos = 0;
let left = 0;
let right = 0;
let inheritanceChain = [mainInterfaceName];
let inh = data[mainInterfaceName] != undefined ? data[mainInterfaceName].inh : '';
function getInheritance(inh) {
if (inh !== '') {
inheritanceChain.unshift(inh);
if (data[inh]) {
inh = data[inh].inh;
getInheritance(inh);
}
}
}
getInheritance(inh);
function rectWithText(x, y, fill, interfaceName, reverse) {
const rectWidth = calculateRectWidth(interfaceName);
if (reverse) x -= rectWidth;
return `
${interfaceName}
`;
}
function lineWithTriangle(x, y, reverse) {
const length = reverse ? -30 : 30;
return `
${triangle(x, y, reverse)}`;
}
function connectingLineWithTriangle(x, y, reverse) {
const width = reverse ? -17 : 17;
return `
${triangle(x, y, reverse)}`;
}
function triangle(x, y, reverse) {
const width = reverse ? -10 : 10;
return ``;
}
function calculateRectWidth(text) {
return text.length * 8 < 75 ? 75 : text.length * 8;
}
function moveBy(number, delta, reverse) {
return number + (reverse ? -delta : delta);
}
function includeInRange(number, start, end) {
return [
Math.min(start, number),
Math.max(end, number)
];
}
function drawDiagram(inheritanceChain) {
let str = '';
let reverse = false;
for (let i = 0; i < inheritanceChain.length; i++) {
const fill = (inheritanceChain[i] == mainInterfaceName) ? '#F4F7F8': '#fff';
const rectWidth = calculateRectWidth(inheritanceChain[i]);
// Minumum space required to continue the current row
let reqSpace = rectWidth;
if (i > 0) reqSpace += 30;
// If the rect from the next iteration won't fit in the row, we need to be
// sure that at least the connectingLineWithTriangle will fit
if (i < inheritanceChain.length - 1) reqSpace += 17;
const reqBounds = includeInRange(
moveBy(xpos, reqSpace, reverse), left, right
);
// Will the current drawing items fit inside the viewbox? Subtract the
// stroke width from the viewbox width to prevent stroke cut off.
const canContinueRow = reqBounds[1] - reqBounds[0] <= 650 - 2;
if (i > 0) {
if (canContinueRow) {
str += lineWithTriangle(xpos, ypos + 14, reverse);
xpos = moveBy(xpos, 30, reverse);
} else {
str += connectingLineWithTriangle(xpos, ypos + 14, reverse);
[left, right] = includeInRange(moveBy(xpos, 17, reverse), left, right);
ypos += 46;
height += 46;
reverse = !reverse;
}
}
str += rectWithText(xpos, ypos, fill, inheritanceChain[i], reverse);
xpos = moveBy(xpos, rectWidth, reverse);
[left, right] = includeInRange(xpos, left, right);
}
return str;
}
let output = '';
if (inheritanceChain.length > 1) {
let diagram = drawDiagram(inheritanceChain); // needs to run first to calculate left and height
output = `';
}
%>
<%-output%>