/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; /** * Draw the treemap into the provided canvases using the 2d context. The treemap * layout is computed with d3. There are 2 canvases provided, each matching * the resolution of the window. The main canvas is a fully drawn version of * the treemap that is positioned and zoomed using css. It gets blurry the more * you zoom in as it doesn't get redrawn when zooming. The zoom canvas is * repositioned absolutely after every change in the dragZoom object, and then * redrawn to provide a full-resolution (non-blurry) view of zoomed in segment * of the treemap.
*/
/** * Setup and start drawing the treemap visualization * * @param {Object} report * @param {Object} canvases * A CanvasUtils object that contains references to the main and zoom * canvases and contexts * @param {Object} dragZoom * A DragZoom object representing the current state of the dragging * and zooming behavior
*/
exports.setupDraw = function (report, canvases, dragZoom) { const getTreemap = configureD3Treemap.bind(null, canvases.main.canvas);
/** * Returns a configured d3 treemap function * * @param {HTMLCanvasElement} canvas * @return {Function}
*/ const configureD3Treemap = (exports.configureD3Treemap = function (canvas) { const window = canvas.ownerDocument.defaultView; const ratio = window.devicePixelRatio; const treemap = window.d3.layout
.treemap()
.size([ // The d3 layout includes the padding around everything, add some // extra padding to the size to compensate for thi
canvas.width + (PADDING[1] + PADDING[3]) * ratio,
canvas.height + (PADDING[0] + PADDING[2]) * ratio,
])
.sticky(true)
.padding([
PADDING[0] * ratio,
PADDING[1] * ratio,
PADDING[2] * ratio,
PADDING[3] * ratio,
])
.value(d => d.bytes);
/** * Create treemap nodes from a census report that are sorted by depth * * @param {Object} report * @return {Array} An array of d3 treemap nodes * // https://github.com/mbostock/d3/wiki/Treemap-Layout * parent - the parent node, or null for the root. * children - the array of child nodes, or null for leaf nodes. * value - the node value, as returned by the value accessor. * depth - the depth of the node, starting at 0 for the root. * area - the computed pixel area of this node. * x - the minimum x-coordinate of the node position. * y - the minimum y-coordinate of the node position. * z - the orientation of this cell’s subdivision, if any. * dx - the x-extent of the node position. * dy - the y-extent of the node position.
*/ returnfunction depthSortedNodes(report) { const nodes = treemap(report);
nodes.sort((a, b) => a.depth - b.depth); return nodes;
};
});
/** * Draw the text, cut it in half every time it doesn't fit until it fits or * it's smaller than the "..." text. * * @param {CanvasRenderingContext2D} ctx * @param {Number} x * the position of the text * @param {Number} y * the position of the text * @param {Number} innerWidth * the inner width of the containing treemap cell * @param {Text} name
*/ const drawTruncatedName = (exports.drawTruncatedName = function (
ctx,
x,
y,
innerWidth,
name
) { const truncated = name.substr(0, Math.floor(name.length / 2)); const formatted = truncated + ELLIPSIS;
if (ctx.measureText(formatted).width > innerWidth) {
drawTruncatedName(ctx, x, y, innerWidth, truncated);
} else {
ctx.fillText(formatted, x, y);
}
});
/** * Fit and draw the text in a node with the following strategies to shrink * down the text size: * * Function 608KB 9083 count * Function * Func... * Fu... * ... * * @param {CanvasRenderingContext2D} ctx * @param {Object} node * @param {Number} borderWidth * @param {Object} dragZoom * @param {Array} padding
*/ const drawText = (exports.drawText = function (
ctx,
node,
borderWidth,
ratio,
dragZoom,
padding
) {
let { dx, dy, name, totalBytes, totalCount } = node; const scale = dragZoom.zoom + 1;
dx *= scale;
dy *= scale;
// Start checking to see how much text we can fit in, optimizing for the // common case of lots of small leaf nodes if (FONT_SIZE * FONT_LINE_HEIGHT < dy) { const margin = borderWidth(node) * 1.5 + ratio * TEXT_MARGIN; const x = margin + (node.x - padding[0]) * scale - dragZoom.offsetX; const y = margin + (node.y - padding[1]) * scale - dragZoom.offsetY; const innerWidth = dx - margin * 2; const nameSize = ctx.measureText(name).width;
if (ctx.measureText(ELLIPSIS).width > innerWidth) { return;
}
ctx.fillStyle = TEXT_COLOR;
if (nameSize > innerWidth) { // The name is too long - halve the name as an expediant way to shorten it
drawTruncatedName(ctx, x, y, innerWidth, name);
} else { const bytesFormatted = formatAbbreviatedBytes(totalBytes); const countFormatted = `${totalCount} ${COUNT_LABEL}`; const byteSize = ctx.measureText(bytesFormatted).width; const countSize = ctx.measureText(countFormatted).width; const spaceSize = ctx.measureText(" ").width;
if (nameSize + byteSize + countSize + spaceSize * 3 > innerWidth) { // The full name will fit
ctx.fillText(`${name}`, x, y);
} else { // The full name plus the byte information will fit
ctx.fillText(name, x, y);
ctx.fillStyle = TEXT_LIGHT_COLOR;
ctx.fillText(
`${bytesFormatted} ${countFormatted}`,
x + nameSize + spaceSize,
y
);
}
}
}
});
/** * Set the position of the zoomed in canvas. It always take up 100% of the view * window, but is transformed relative to the zoomed in containing element, * essentially reversing the transform of the containing element. * * @param {HTMLCanvasElement} canvas * @param {Object} dragZoom
*/ const positionZoomedCanvas = function (canvas, dragZoom) { const scale = 1 / (1 + dragZoom.zoom); const x = -dragZoom.translateX; const y = -dragZoom.translateY;
canvas.style.transform = `scale(${scale}) translate(${x}px, ${y}px)`;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.