mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
add features for border-style dashed, dotted, double. (#2531)
This commit is contained in:
parent
2a013e20c8
commit
72cd528429
@ -1,7 +1,10 @@
|
||||
import {IPropertyIdentValueDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor';
|
||||
export enum BORDER_STYLE {
|
||||
NONE = 0,
|
||||
SOLID = 1
|
||||
SOLID = 1,
|
||||
DASHED = 2,
|
||||
DOTTED = 3,
|
||||
DOUBLE = 4
|
||||
}
|
||||
|
||||
const borderStyleForSide = (side: string): IPropertyIdentValueDescriptor<BORDER_STYLE> => ({
|
||||
@ -13,6 +16,12 @@ const borderStyleForSide = (side: string): IPropertyIdentValueDescriptor<BORDER_
|
||||
switch (style) {
|
||||
case 'none':
|
||||
return BORDER_STYLE.NONE;
|
||||
case 'dashed':
|
||||
return BORDER_STYLE.DASHED;
|
||||
case 'dotted':
|
||||
return BORDER_STYLE.DOTTED;
|
||||
case 'double':
|
||||
return BORDER_STYLE.DOUBLE;
|
||||
}
|
||||
return BORDER_STYLE.SOLID;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ export const display: IPropertyListDescriptor<Display> = {
|
||||
const parseDisplayValue = (display: string): Display => {
|
||||
switch (display) {
|
||||
case 'block':
|
||||
case '-webkit-box':
|
||||
return DISPLAY.BLOCK;
|
||||
case 'inline':
|
||||
return DISPLAY.INLINE;
|
||||
|
6
src/global.d.ts
vendored
6
src/global.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
interface CSSStyleDeclaration {
|
||||
textDecorationColor: string | null;
|
||||
textDecorationLine: string | null;
|
||||
overflowWrap: string | null;
|
||||
textDecorationColor: string;
|
||||
textDecorationLine: string;
|
||||
overflowWrap: string;
|
||||
}
|
||||
|
||||
interface DocumentType extends Node, ChildNode {
|
||||
|
@ -36,6 +36,105 @@ export const parsePathForBorder = (curves: BoundCurves, borderSide: number): Pat
|
||||
}
|
||||
};
|
||||
|
||||
export const parsePathForBorderDoubleOuter = (curves: BoundCurves, borderSide: number): Path[] => {
|
||||
switch (borderSide) {
|
||||
case 0:
|
||||
return createPathFromCurves(
|
||||
curves.topLeftBorderBox,
|
||||
curves.topLeftBorderDoubleOuterBox,
|
||||
curves.topRightBorderBox,
|
||||
curves.topRightBorderDoubleOuterBox
|
||||
);
|
||||
case 1:
|
||||
return createPathFromCurves(
|
||||
curves.topRightBorderBox,
|
||||
curves.topRightBorderDoubleOuterBox,
|
||||
curves.bottomRightBorderBox,
|
||||
curves.bottomRightBorderDoubleOuterBox
|
||||
);
|
||||
case 2:
|
||||
return createPathFromCurves(
|
||||
curves.bottomRightBorderBox,
|
||||
curves.bottomRightBorderDoubleOuterBox,
|
||||
curves.bottomLeftBorderBox,
|
||||
curves.bottomLeftBorderDoubleOuterBox
|
||||
);
|
||||
case 3:
|
||||
default:
|
||||
return createPathFromCurves(
|
||||
curves.bottomLeftBorderBox,
|
||||
curves.bottomLeftBorderDoubleOuterBox,
|
||||
curves.topLeftBorderBox,
|
||||
curves.topLeftBorderDoubleOuterBox
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const parsePathForBorderDoubleInner = (curves: BoundCurves, borderSide: number): Path[] => {
|
||||
switch (borderSide) {
|
||||
case 0:
|
||||
return createPathFromCurves(
|
||||
curves.topLeftBorderDoubleInnerBox,
|
||||
curves.topLeftPaddingBox,
|
||||
curves.topRightBorderDoubleInnerBox,
|
||||
curves.topRightPaddingBox
|
||||
);
|
||||
case 1:
|
||||
return createPathFromCurves(
|
||||
curves.topRightBorderDoubleInnerBox,
|
||||
curves.topRightPaddingBox,
|
||||
curves.bottomRightBorderDoubleInnerBox,
|
||||
curves.bottomRightPaddingBox
|
||||
);
|
||||
case 2:
|
||||
return createPathFromCurves(
|
||||
curves.bottomRightBorderDoubleInnerBox,
|
||||
curves.bottomRightPaddingBox,
|
||||
curves.bottomLeftBorderDoubleInnerBox,
|
||||
curves.bottomLeftPaddingBox
|
||||
);
|
||||
case 3:
|
||||
default:
|
||||
return createPathFromCurves(
|
||||
curves.bottomLeftBorderDoubleInnerBox,
|
||||
curves.bottomLeftPaddingBox,
|
||||
curves.topLeftBorderDoubleInnerBox,
|
||||
curves.topLeftPaddingBox
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const parsePathForBorderStroke = (curves: BoundCurves, borderSide: number): Path[] => {
|
||||
switch (borderSide) {
|
||||
case 0:
|
||||
return createStrokePathFromCurves(curves.topLeftBorderStroke, curves.topRightBorderStroke);
|
||||
case 1:
|
||||
return createStrokePathFromCurves(curves.topRightBorderStroke, curves.bottomRightBorderStroke);
|
||||
case 2:
|
||||
return createStrokePathFromCurves(curves.bottomRightBorderStroke, curves.bottomLeftBorderStroke);
|
||||
case 3:
|
||||
default:
|
||||
return createStrokePathFromCurves(curves.bottomLeftBorderStroke, curves.topLeftBorderStroke);
|
||||
}
|
||||
};
|
||||
|
||||
const createStrokePathFromCurves = (outer1: Path, outer2: Path): Path[] => {
|
||||
const path = [];
|
||||
if (isBezierCurve(outer1)) {
|
||||
path.push(outer1.subdivide(0.5, false));
|
||||
} else {
|
||||
path.push(outer1);
|
||||
}
|
||||
|
||||
if (isBezierCurve(outer2)) {
|
||||
path.push(outer2.subdivide(0.5, true));
|
||||
} else {
|
||||
path.push(outer2);
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
const createPathFromCurves = (outer1: Path, inner1: Path, outer2: Path, inner2: Path): Path[] => {
|
||||
const path = [];
|
||||
if (isBezierCurve(outer1)) {
|
||||
|
@ -5,6 +5,18 @@ import {BezierCurve} from './bezier-curve';
|
||||
import {Path} from './path';
|
||||
|
||||
export class BoundCurves {
|
||||
readonly topLeftBorderDoubleOuterBox: Path;
|
||||
readonly topRightBorderDoubleOuterBox: Path;
|
||||
readonly bottomRightBorderDoubleOuterBox: Path;
|
||||
readonly bottomLeftBorderDoubleOuterBox: Path;
|
||||
readonly topLeftBorderDoubleInnerBox: Path;
|
||||
readonly topRightBorderDoubleInnerBox: Path;
|
||||
readonly bottomRightBorderDoubleInnerBox: Path;
|
||||
readonly bottomLeftBorderDoubleInnerBox: Path;
|
||||
readonly topLeftBorderStroke: Path;
|
||||
readonly topRightBorderStroke: Path;
|
||||
readonly bottomRightBorderStroke: Path;
|
||||
readonly bottomLeftBorderStroke: Path;
|
||||
readonly topLeftBorderBox: Path;
|
||||
readonly topRightBorderBox: Path;
|
||||
readonly bottomRightBorderBox: Path;
|
||||
@ -60,6 +72,141 @@ export class BoundCurves {
|
||||
const paddingBottom = getAbsoluteValue(styles.paddingBottom, element.bounds.width);
|
||||
const paddingLeft = getAbsoluteValue(styles.paddingLeft, element.bounds.width);
|
||||
|
||||
this.topLeftBorderDoubleOuterBox =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + borderLeftWidth / 3,
|
||||
bounds.top + borderTopWidth / 3,
|
||||
tlh - borderLeftWidth / 3,
|
||||
tlv - borderTopWidth / 3,
|
||||
CORNER.TOP_LEFT
|
||||
)
|
||||
: new Vector(bounds.left + borderLeftWidth / 3, bounds.top + borderTopWidth / 3);
|
||||
this.topRightBorderDoubleOuterBox =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + topWidth,
|
||||
bounds.top + borderTopWidth / 3,
|
||||
trh - borderRightWidth / 3,
|
||||
trv - borderTopWidth / 3,
|
||||
CORNER.TOP_RIGHT
|
||||
)
|
||||
: new Vector(bounds.left + bounds.width - borderRightWidth / 3, bounds.top + borderTopWidth / 3);
|
||||
this.bottomRightBorderDoubleOuterBox =
|
||||
brh > 0 || brv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + bottomWidth,
|
||||
bounds.top + rightHeight,
|
||||
brh - borderRightWidth / 3,
|
||||
brv - borderBottomWidth / 3,
|
||||
CORNER.BOTTOM_RIGHT
|
||||
)
|
||||
: new Vector(
|
||||
bounds.left + bounds.width - borderRightWidth / 3,
|
||||
bounds.top + bounds.height - borderBottomWidth / 3
|
||||
);
|
||||
this.bottomLeftBorderDoubleOuterBox =
|
||||
blh > 0 || blv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + borderLeftWidth / 3,
|
||||
bounds.top + leftHeight,
|
||||
blh - borderLeftWidth / 3,
|
||||
blv - borderBottomWidth / 3,
|
||||
CORNER.BOTTOM_LEFT
|
||||
)
|
||||
: new Vector(bounds.left + borderLeftWidth / 3, bounds.top + bounds.height - borderBottomWidth / 3);
|
||||
this.topLeftBorderDoubleInnerBox =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + (borderLeftWidth * 2) / 3,
|
||||
bounds.top + (borderTopWidth * 2) / 3,
|
||||
tlh - (borderLeftWidth * 2) / 3,
|
||||
tlv - (borderTopWidth * 2) / 3,
|
||||
CORNER.TOP_LEFT
|
||||
)
|
||||
: new Vector(bounds.left + (borderLeftWidth * 2) / 3, bounds.top + (borderTopWidth * 2) / 3);
|
||||
this.topRightBorderDoubleInnerBox =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + topWidth,
|
||||
bounds.top + (borderTopWidth * 2) / 3,
|
||||
trh - (borderRightWidth * 2) / 3,
|
||||
trv - (borderTopWidth * 2) / 3,
|
||||
CORNER.TOP_RIGHT
|
||||
)
|
||||
: new Vector(
|
||||
bounds.left + bounds.width - (borderRightWidth * 2) / 3,
|
||||
bounds.top + (borderTopWidth * 2) / 3
|
||||
);
|
||||
this.bottomRightBorderDoubleInnerBox =
|
||||
brh > 0 || brv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + bottomWidth,
|
||||
bounds.top + rightHeight,
|
||||
brh - (borderRightWidth * 2) / 3,
|
||||
brv - (borderBottomWidth * 2) / 3,
|
||||
CORNER.BOTTOM_RIGHT
|
||||
)
|
||||
: new Vector(
|
||||
bounds.left + bounds.width - (borderRightWidth * 2) / 3,
|
||||
bounds.top + bounds.height - (borderBottomWidth * 2) / 3
|
||||
);
|
||||
this.bottomLeftBorderDoubleInnerBox =
|
||||
blh > 0 || blv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + (borderLeftWidth * 2) / 3,
|
||||
bounds.top + leftHeight,
|
||||
blh - (borderLeftWidth * 2) / 3,
|
||||
blv - (borderBottomWidth * 2) / 3,
|
||||
CORNER.BOTTOM_LEFT
|
||||
)
|
||||
: new Vector(
|
||||
bounds.left + (borderLeftWidth * 2) / 3,
|
||||
bounds.top + bounds.height - (borderBottomWidth * 2) / 3
|
||||
);
|
||||
this.topLeftBorderStroke =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + borderLeftWidth / 2,
|
||||
bounds.top + borderTopWidth / 2,
|
||||
tlh - borderLeftWidth / 2,
|
||||
tlv - borderTopWidth / 2,
|
||||
CORNER.TOP_LEFT
|
||||
)
|
||||
: new Vector(bounds.left + borderLeftWidth / 2, bounds.top + borderTopWidth / 2);
|
||||
this.topRightBorderStroke =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + topWidth,
|
||||
bounds.top + borderTopWidth / 2,
|
||||
trh - borderRightWidth / 2,
|
||||
trv - borderTopWidth / 2,
|
||||
CORNER.TOP_RIGHT
|
||||
)
|
||||
: new Vector(bounds.left + bounds.width - borderRightWidth / 2, bounds.top + borderTopWidth / 2);
|
||||
this.bottomRightBorderStroke =
|
||||
brh > 0 || brv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + bottomWidth,
|
||||
bounds.top + rightHeight,
|
||||
brh - borderRightWidth / 2,
|
||||
brv - borderBottomWidth / 2,
|
||||
CORNER.BOTTOM_RIGHT
|
||||
)
|
||||
: new Vector(
|
||||
bounds.left + bounds.width - borderRightWidth / 2,
|
||||
bounds.top + bounds.height - borderBottomWidth / 2
|
||||
);
|
||||
this.bottomLeftBorderStroke =
|
||||
blh > 0 || blv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + borderLeftWidth / 2,
|
||||
bounds.top + leftHeight,
|
||||
blh - borderLeftWidth / 2,
|
||||
blv - borderBottomWidth / 2,
|
||||
CORNER.BOTTOM_LEFT
|
||||
)
|
||||
: new Vector(bounds.left + borderLeftWidth / 2, bounds.top + bounds.height - borderBottomWidth / 2);
|
||||
this.topLeftBorderBox =
|
||||
tlh > 0 || tlv > 0
|
||||
? getCurvePoints(bounds.left, bounds.top, tlh, tlv, CORNER.TOP_LEFT)
|
||||
@ -89,10 +236,10 @@ export class BoundCurves {
|
||||
this.topRightPaddingBox =
|
||||
trh > 0 || trv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + Math.min(topWidth, bounds.width + borderLeftWidth),
|
||||
bounds.left + Math.min(topWidth, bounds.width - borderRightWidth),
|
||||
bounds.top + borderTopWidth,
|
||||
topWidth > bounds.width + borderRightWidth ? 0 : trh - borderRightWidth,
|
||||
trv - borderTopWidth,
|
||||
topWidth > bounds.width + borderRightWidth ? 0 : Math.max(0, trh - borderRightWidth),
|
||||
Math.max(0, trv - borderTopWidth),
|
||||
CORNER.TOP_RIGHT
|
||||
)
|
||||
: new Vector(bounds.left + bounds.width - borderRightWidth, bounds.top + borderTopWidth);
|
||||
@ -100,9 +247,9 @@ export class BoundCurves {
|
||||
brh > 0 || brv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + Math.min(bottomWidth, bounds.width - borderLeftWidth),
|
||||
bounds.top + Math.min(rightHeight, bounds.height + borderTopWidth),
|
||||
bounds.top + Math.min(rightHeight, bounds.height - borderBottomWidth),
|
||||
Math.max(0, brh - borderRightWidth),
|
||||
brv - borderBottomWidth,
|
||||
Math.max(0, brv - borderBottomWidth),
|
||||
CORNER.BOTTOM_RIGHT
|
||||
)
|
||||
: new Vector(
|
||||
@ -113,9 +260,9 @@ export class BoundCurves {
|
||||
blh > 0 || blv > 0
|
||||
? getCurvePoints(
|
||||
bounds.left + borderLeftWidth,
|
||||
bounds.top + leftHeight,
|
||||
bounds.top + Math.min(leftHeight, bounds.height - borderBottomWidth),
|
||||
Math.max(0, blh - borderLeftWidth),
|
||||
blv - borderBottomWidth,
|
||||
Math.max(0, blv - borderBottomWidth),
|
||||
CORNER.BOTTOM_LEFT
|
||||
)
|
||||
: new Vector(bounds.left + borderLeftWidth, bounds.top + bounds.height - borderBottomWidth);
|
||||
|
@ -8,10 +8,15 @@ import {TextContainer} from '../../dom/text-container';
|
||||
import {Path, transformPath} from '../path';
|
||||
import {BACKGROUND_CLIP} from '../../css/property-descriptors/background-clip';
|
||||
import {BoundCurves, calculateBorderBoxPath, calculateContentBoxPath, calculatePaddingBoxPath} from '../bound-curves';
|
||||
import {isBezierCurve} from '../bezier-curve';
|
||||
import {BezierCurve, isBezierCurve} from '../bezier-curve';
|
||||
import {Vector} from '../vector';
|
||||
import {CSSImageType, CSSURLImage, isLinearGradient, isRadialGradient} from '../../css/types/image';
|
||||
import {parsePathForBorder} from '../border';
|
||||
import {
|
||||
parsePathForBorder,
|
||||
parsePathForBorderDoubleInner,
|
||||
parsePathForBorderDoubleOuter,
|
||||
parsePathForBorderStroke
|
||||
} from '../border';
|
||||
import {Cache} from '../../core/cache-storage';
|
||||
import {calculateBackgroundRendering, getBackgroundValueForIndex} from '../background';
|
||||
import {isDimensionToken} from '../../css/syntax/parser';
|
||||
@ -630,22 +635,37 @@ export class CanvasRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
async renderBorder(color: Color, side: number, curvePoints: BoundCurves) {
|
||||
async renderSolidBorder(color: Color, side: number, curvePoints: BoundCurves) {
|
||||
this.path(parsePathForBorder(curvePoints, side));
|
||||
this.ctx.fillStyle = asString(color);
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
async renderDoubleBorder(color: Color, width: number, side: number, curvePoints: BoundCurves) {
|
||||
if (width < 3) {
|
||||
await this.renderSolidBorder(color, side, curvePoints);
|
||||
return;
|
||||
}
|
||||
|
||||
const outerPaths = parsePathForBorderDoubleOuter(curvePoints, side);
|
||||
this.path(outerPaths);
|
||||
this.ctx.fillStyle = asString(color);
|
||||
this.ctx.fill();
|
||||
const innerPaths = parsePathForBorderDoubleInner(curvePoints, side);
|
||||
this.path(innerPaths);
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
async renderNodeBackgroundAndBorders(paint: ElementPaint) {
|
||||
this.applyEffects(paint.effects, EffectTarget.BACKGROUND_BORDERS);
|
||||
const styles = paint.container.styles;
|
||||
const hasBackground = !isTransparent(styles.backgroundColor) || styles.backgroundImage.length;
|
||||
|
||||
const borders = [
|
||||
{style: styles.borderTopStyle, color: styles.borderTopColor},
|
||||
{style: styles.borderRightStyle, color: styles.borderRightColor},
|
||||
{style: styles.borderBottomStyle, color: styles.borderBottomColor},
|
||||
{style: styles.borderLeftStyle, color: styles.borderLeftColor}
|
||||
{style: styles.borderTopStyle, color: styles.borderTopColor, width: styles.borderTopWidth},
|
||||
{style: styles.borderRightStyle, color: styles.borderRightColor, width: styles.borderRightWidth},
|
||||
{style: styles.borderBottomStyle, color: styles.borderBottomColor, width: styles.borderBottomWidth},
|
||||
{style: styles.borderLeftStyle, color: styles.borderLeftColor, width: styles.borderLeftWidth}
|
||||
];
|
||||
|
||||
const backgroundPaintingArea = calculateBackgroundCurvedPaintingArea(
|
||||
@ -705,13 +725,143 @@ export class CanvasRenderer {
|
||||
|
||||
let side = 0;
|
||||
for (const border of borders) {
|
||||
if (border.style !== BORDER_STYLE.NONE && !isTransparent(border.color)) {
|
||||
await this.renderBorder(border.color, side, paint.curves);
|
||||
if (border.style !== BORDER_STYLE.NONE && !isTransparent(border.color) && border.width > 0) {
|
||||
if (border.style === BORDER_STYLE.DASHED) {
|
||||
await this.renderDashedDottedBorder(
|
||||
border.color,
|
||||
border.width,
|
||||
side,
|
||||
paint.curves,
|
||||
BORDER_STYLE.DASHED
|
||||
);
|
||||
} else if (border.style === BORDER_STYLE.DOTTED) {
|
||||
await this.renderDashedDottedBorder(
|
||||
border.color,
|
||||
border.width,
|
||||
side,
|
||||
paint.curves,
|
||||
BORDER_STYLE.DOTTED
|
||||
);
|
||||
} else if (border.style === BORDER_STYLE.DOUBLE) {
|
||||
await this.renderDoubleBorder(border.color, border.width, side, paint.curves);
|
||||
} else {
|
||||
await this.renderSolidBorder(border.color, side, paint.curves);
|
||||
}
|
||||
}
|
||||
side++;
|
||||
}
|
||||
}
|
||||
|
||||
async renderDashedDottedBorder(
|
||||
color: Color,
|
||||
width: number,
|
||||
side: number,
|
||||
curvePoints: BoundCurves,
|
||||
style: BORDER_STYLE
|
||||
) {
|
||||
this.ctx.save();
|
||||
|
||||
const strokePaths = parsePathForBorderStroke(curvePoints, side);
|
||||
const boxPaths = parsePathForBorder(curvePoints, side);
|
||||
|
||||
if (style === BORDER_STYLE.DASHED) {
|
||||
this.path(boxPaths);
|
||||
this.ctx.clip();
|
||||
}
|
||||
|
||||
let startX, startY, endX, endY;
|
||||
if (isBezierCurve(boxPaths[0])) {
|
||||
startX = (boxPaths[0] as BezierCurve).start.x;
|
||||
startY = (boxPaths[0] as BezierCurve).start.y;
|
||||
} else {
|
||||
startX = (boxPaths[0] as Vector).x;
|
||||
startY = (boxPaths[0] as Vector).y;
|
||||
}
|
||||
if (isBezierCurve(boxPaths[1])) {
|
||||
endX = (boxPaths[1] as BezierCurve).end.x;
|
||||
endY = (boxPaths[1] as BezierCurve).end.y;
|
||||
} else {
|
||||
endX = (boxPaths[1] as Vector).x;
|
||||
endY = (boxPaths[1] as Vector).y;
|
||||
}
|
||||
|
||||
let length;
|
||||
if (side === 0 || side === 2) {
|
||||
length = Math.abs(startX - endX);
|
||||
} else {
|
||||
length = Math.abs(startY - endY);
|
||||
}
|
||||
|
||||
this.ctx.beginPath();
|
||||
if (style === BORDER_STYLE.DOTTED) {
|
||||
this.formatPath(strokePaths);
|
||||
} else {
|
||||
this.formatPath(boxPaths.slice(0, 2));
|
||||
}
|
||||
|
||||
let dashLength = width < 3 ? width * 3 : width * 2;
|
||||
let spaceLength = width < 3 ? width * 2 : width;
|
||||
if (style === BORDER_STYLE.DOTTED) {
|
||||
dashLength = width;
|
||||
spaceLength = width;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (useLineDash) {
|
||||
if (style === BORDER_STYLE.DOTTED) {
|
||||
this.ctx.setLineDash([0, dashLength + spaceLength]);
|
||||
} else {
|
||||
this.ctx.setLineDash([dashLength, spaceLength]);
|
||||
}
|
||||
}
|
||||
|
||||
if (style === BORDER_STYLE.DOTTED) {
|
||||
this.ctx.lineCap = 'round';
|
||||
this.ctx.lineWidth = width;
|
||||
} else {
|
||||
this.ctx.lineWidth = width * 2 + 1.1;
|
||||
}
|
||||
this.ctx.strokeStyle = asString(color);
|
||||
this.ctx.stroke();
|
||||
this.ctx.setLineDash([]);
|
||||
|
||||
// dashed round edge gap
|
||||
if (style === BORDER_STYLE.DASHED) {
|
||||
if (isBezierCurve(boxPaths[0])) {
|
||||
const path1 = boxPaths[3] as BezierCurve;
|
||||
const path2 = boxPaths[0] as BezierCurve;
|
||||
this.ctx.beginPath();
|
||||
this.formatPath([new Vector(path1.end.x, path1.end.y), new Vector(path2.start.x, path2.start.y)]);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
if (isBezierCurve(boxPaths[1])) {
|
||||
const path1 = boxPaths[1] as BezierCurve;
|
||||
const path2 = boxPaths[2] as BezierCurve;
|
||||
this.ctx.beginPath();
|
||||
this.formatPath([new Vector(path1.end.x, path1.end.y), new Vector(path2.start.x, path2.start.y)]);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
this.ctx.restore();
|
||||
}
|
||||
|
||||
async render(element: ElementContainer): Promise<HTMLCanvasElement> {
|
||||
if (this.options.backgroundColor) {
|
||||
this.ctx.fillStyle = asString(this.options.backgroundColor);
|
||||
|
@ -23,10 +23,11 @@ const servers: Server[] = [];
|
||||
servers.push(screenshotApp.listen(8000));
|
||||
servers.push(corsApp.listen(8081));
|
||||
|
||||
karmaTestRunner().then(() => {
|
||||
servers.forEach(server => server.close());
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
karmaTestRunner()
|
||||
.then(() => {
|
||||
servers.forEach(server => server.close());
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user