html2canvas-pro
Version:
Screenshots with JavaScript. Next generation!
185 lines • 6.82 kB
JavaScript
"use strict";
/**
* Border Renderer
*
* Handles rendering of element borders including:
* - Solid borders
* - Double borders
* - Dashed borders
* - Dotted borders
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BorderRenderer = void 0;
const color_utilities_1 = require("../../css/types/color-utilities");
const border_1 = require("../border");
const bezier_curve_1 = require("../bezier-curve");
const vector_1 = require("../vector");
/**
* Border Renderer
*
* Specialized renderer for element borders.
* Extracted from CanvasRenderer to improve code organization and maintainability.
*/
class BorderRenderer {
constructor(deps, pathCallbacks) {
this.ctx = deps.ctx;
this.pathCallbacks = pathCallbacks;
}
/**
* Render a solid border
*
* @param color - Border color
* @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
* @param curvePoints - Border curve points
*/
async renderSolidBorder(color, side, curvePoints) {
this.pathCallbacks.path((0, border_1.parsePathForBorder)(curvePoints, side));
this.ctx.fillStyle = (0, color_utilities_1.asString)(color);
this.ctx.fill();
}
/**
* Render a double border
* Falls back to solid border if width is too small
*
* @param color - Border color
* @param width - Border width
* @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
* @param curvePoints - Border curve points
*/
async renderDoubleBorder(color, width, side, curvePoints) {
if (width < 3) {
await this.renderSolidBorder(color, side, curvePoints);
return;
}
const outerPaths = (0, border_1.parsePathForBorderDoubleOuter)(curvePoints, side);
this.pathCallbacks.path(outerPaths);
this.ctx.fillStyle = (0, color_utilities_1.asString)(color);
this.ctx.fill();
const innerPaths = (0, border_1.parsePathForBorderDoubleInner)(curvePoints, side);
this.pathCallbacks.path(innerPaths);
this.ctx.fill();
}
/**
* Render a dashed or dotted border
*
* @param color - Border color
* @param width - Border width
* @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
* @param curvePoints - Border curve points
* @param style - Border style (DASHED or DOTTED)
*/
async renderDashedDottedBorder(color, width, side, curvePoints, style) {
this.ctx.save();
const strokePaths = (0, border_1.parsePathForBorderStroke)(curvePoints, side);
const boxPaths = (0, border_1.parsePathForBorder)(curvePoints, side);
if (style === 2 /* BORDER_STYLE.DASHED */) {
this.pathCallbacks.path(boxPaths);
this.ctx.clip();
}
// Extract start and end coordinates
let startX, startY, endX, endY;
if ((0, bezier_curve_1.isBezierCurve)(boxPaths[0])) {
startX = boxPaths[0].start.x;
startY = boxPaths[0].start.y;
}
else {
startX = boxPaths[0].x;
startY = boxPaths[0].y;
}
if ((0, bezier_curve_1.isBezierCurve)(boxPaths[1])) {
endX = boxPaths[1].end.x;
endY = boxPaths[1].end.y;
}
else {
endX = boxPaths[1].x;
endY = boxPaths[1].y;
}
// Calculate border length
let length;
if (side === 0 || side === 2) {
length = Math.abs(startX - endX);
}
else {
length = Math.abs(startY - endY);
}
this.ctx.beginPath();
if (style === 3 /* BORDER_STYLE.DOTTED */) {
this.pathCallbacks.formatPath(strokePaths);
}
else {
this.pathCallbacks.formatPath(boxPaths.slice(0, 2));
}
// Calculate dash and space lengths
let dashLength = width < 3 ? width * 3 : width * 2;
let spaceLength = width < 3 ? width * 2 : width;
if (style === 3 /* BORDER_STYLE.DOTTED */) {
dashLength = width;
spaceLength = width;
}
// Adjust dash pattern for border length
let useLineDash = true;
if (length <= dashLength * 2) {
useLineDash = false;
}
else if (length <= dashLength * 2 + spaceLength) {
const multiplier = length / (2 * dashLength + spaceLength);
dashLength *= multiplier;
spaceLength *= multiplier;
}
else {
const numberOfDashes = Math.floor((length + spaceLength) / (dashLength + spaceLength));
const minSpace = (length - numberOfDashes * dashLength) / (numberOfDashes - 1);
const maxSpace = (length - (numberOfDashes + 1) * dashLength) / numberOfDashes;
spaceLength =
maxSpace <= 0 || Math.abs(spaceLength - minSpace) < Math.abs(spaceLength - maxSpace)
? minSpace
: maxSpace;
}
// Apply line dash pattern
if (useLineDash) {
if (style === 3 /* BORDER_STYLE.DOTTED */) {
this.ctx.setLineDash([0, dashLength + spaceLength]);
}
else {
this.ctx.setLineDash([dashLength, spaceLength]);
}
}
// Set line style and stroke
if (style === 3 /* BORDER_STYLE.DOTTED */) {
this.ctx.lineCap = 'round';
this.ctx.lineWidth = width;
}
else {
this.ctx.lineWidth = width * 2 + 1.1;
}
this.ctx.strokeStyle = (0, color_utilities_1.asString)(color);
this.ctx.stroke();
this.ctx.setLineDash([]);
// Fill dashed round edge gaps
if (style === 2 /* BORDER_STYLE.DASHED */) {
if ((0, bezier_curve_1.isBezierCurve)(boxPaths[0])) {
const path1 = boxPaths[3];
const path2 = boxPaths[0];
this.ctx.beginPath();
this.pathCallbacks.formatPath([
new vector_1.Vector(path1.end.x, path1.end.y),
new vector_1.Vector(path2.start.x, path2.start.y)
]);
this.ctx.stroke();
}
if ((0, bezier_curve_1.isBezierCurve)(boxPaths[1])) {
const path1 = boxPaths[1];
const path2 = boxPaths[2];
this.ctx.beginPath();
this.pathCallbacks.formatPath([
new vector_1.Vector(path1.end.x, path1.end.y),
new vector_1.Vector(path2.start.x, path2.start.y)
]);
this.ctx.stroke();
}
}
this.ctx.restore();
}
}
exports.BorderRenderer = BorderRenderer;
//# sourceMappingURL=border-renderer.js.map