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';
|
import {IPropertyIdentValueDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor';
|
||||||
export enum BORDER_STYLE {
|
export enum BORDER_STYLE {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
SOLID = 1
|
SOLID = 1,
|
||||||
|
DASHED = 2,
|
||||||
|
DOTTED = 3,
|
||||||
|
DOUBLE = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
const borderStyleForSide = (side: string): IPropertyIdentValueDescriptor<BORDER_STYLE> => ({
|
const borderStyleForSide = (side: string): IPropertyIdentValueDescriptor<BORDER_STYLE> => ({
|
||||||
@ -13,6 +16,12 @@ const borderStyleForSide = (side: string): IPropertyIdentValueDescriptor<BORDER_
|
|||||||
switch (style) {
|
switch (style) {
|
||||||
case 'none':
|
case 'none':
|
||||||
return BORDER_STYLE.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;
|
return BORDER_STYLE.SOLID;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ export const display: IPropertyListDescriptor<Display> = {
|
|||||||
const parseDisplayValue = (display: string): Display => {
|
const parseDisplayValue = (display: string): Display => {
|
||||||
switch (display) {
|
switch (display) {
|
||||||
case 'block':
|
case 'block':
|
||||||
|
case '-webkit-box':
|
||||||
return DISPLAY.BLOCK;
|
return DISPLAY.BLOCK;
|
||||||
case 'inline':
|
case 'inline':
|
||||||
return DISPLAY.INLINE;
|
return DISPLAY.INLINE;
|
||||||
|
6
src/global.d.ts
vendored
6
src/global.d.ts
vendored
@ -1,7 +1,7 @@
|
|||||||
interface CSSStyleDeclaration {
|
interface CSSStyleDeclaration {
|
||||||
textDecorationColor: string | null;
|
textDecorationColor: string;
|
||||||
textDecorationLine: string | null;
|
textDecorationLine: string;
|
||||||
overflowWrap: string | null;
|
overflowWrap: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DocumentType extends Node, ChildNode {
|
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 createPathFromCurves = (outer1: Path, inner1: Path, outer2: Path, inner2: Path): Path[] => {
|
||||||
const path = [];
|
const path = [];
|
||||||
if (isBezierCurve(outer1)) {
|
if (isBezierCurve(outer1)) {
|
||||||
|
@ -5,6 +5,18 @@ import {BezierCurve} from './bezier-curve';
|
|||||||
import {Path} from './path';
|
import {Path} from './path';
|
||||||
|
|
||||||
export class BoundCurves {
|
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 topLeftBorderBox: Path;
|
||||||
readonly topRightBorderBox: Path;
|
readonly topRightBorderBox: Path;
|
||||||
readonly bottomRightBorderBox: Path;
|
readonly bottomRightBorderBox: Path;
|
||||||
@ -60,6 +72,141 @@ export class BoundCurves {
|
|||||||
const paddingBottom = getAbsoluteValue(styles.paddingBottom, element.bounds.width);
|
const paddingBottom = getAbsoluteValue(styles.paddingBottom, element.bounds.width);
|
||||||
const paddingLeft = getAbsoluteValue(styles.paddingLeft, 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 =
|
this.topLeftBorderBox =
|
||||||
tlh > 0 || tlv > 0
|
tlh > 0 || tlv > 0
|
||||||
? getCurvePoints(bounds.left, bounds.top, tlh, tlv, CORNER.TOP_LEFT)
|
? getCurvePoints(bounds.left, bounds.top, tlh, tlv, CORNER.TOP_LEFT)
|
||||||
@ -89,10 +236,10 @@ export class BoundCurves {
|
|||||||
this.topRightPaddingBox =
|
this.topRightPaddingBox =
|
||||||
trh > 0 || trv > 0
|
trh > 0 || trv > 0
|
||||||
? getCurvePoints(
|
? getCurvePoints(
|
||||||
bounds.left + Math.min(topWidth, bounds.width + borderLeftWidth),
|
bounds.left + Math.min(topWidth, bounds.width - borderRightWidth),
|
||||||
bounds.top + borderTopWidth,
|
bounds.top + borderTopWidth,
|
||||||
topWidth > bounds.width + borderRightWidth ? 0 : trh - borderRightWidth,
|
topWidth > bounds.width + borderRightWidth ? 0 : Math.max(0, trh - borderRightWidth),
|
||||||
trv - borderTopWidth,
|
Math.max(0, trv - borderTopWidth),
|
||||||
CORNER.TOP_RIGHT
|
CORNER.TOP_RIGHT
|
||||||
)
|
)
|
||||||
: new Vector(bounds.left + bounds.width - borderRightWidth, bounds.top + borderTopWidth);
|
: new Vector(bounds.left + bounds.width - borderRightWidth, bounds.top + borderTopWidth);
|
||||||
@ -100,9 +247,9 @@ export class BoundCurves {
|
|||||||
brh > 0 || brv > 0
|
brh > 0 || brv > 0
|
||||||
? getCurvePoints(
|
? getCurvePoints(
|
||||||
bounds.left + Math.min(bottomWidth, bounds.width - borderLeftWidth),
|
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),
|
Math.max(0, brh - borderRightWidth),
|
||||||
brv - borderBottomWidth,
|
Math.max(0, brv - borderBottomWidth),
|
||||||
CORNER.BOTTOM_RIGHT
|
CORNER.BOTTOM_RIGHT
|
||||||
)
|
)
|
||||||
: new Vector(
|
: new Vector(
|
||||||
@ -113,9 +260,9 @@ export class BoundCurves {
|
|||||||
blh > 0 || blv > 0
|
blh > 0 || blv > 0
|
||||||
? getCurvePoints(
|
? getCurvePoints(
|
||||||
bounds.left + borderLeftWidth,
|
bounds.left + borderLeftWidth,
|
||||||
bounds.top + leftHeight,
|
bounds.top + Math.min(leftHeight, bounds.height - borderBottomWidth),
|
||||||
Math.max(0, blh - borderLeftWidth),
|
Math.max(0, blh - borderLeftWidth),
|
||||||
blv - borderBottomWidth,
|
Math.max(0, blv - borderBottomWidth),
|
||||||
CORNER.BOTTOM_LEFT
|
CORNER.BOTTOM_LEFT
|
||||||
)
|
)
|
||||||
: new Vector(bounds.left + borderLeftWidth, bounds.top + bounds.height - borderBottomWidth);
|
: 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 {Path, transformPath} from '../path';
|
||||||
import {BACKGROUND_CLIP} from '../../css/property-descriptors/background-clip';
|
import {BACKGROUND_CLIP} from '../../css/property-descriptors/background-clip';
|
||||||
import {BoundCurves, calculateBorderBoxPath, calculateContentBoxPath, calculatePaddingBoxPath} from '../bound-curves';
|
import {BoundCurves, calculateBorderBoxPath, calculateContentBoxPath, calculatePaddingBoxPath} from '../bound-curves';
|
||||||
import {isBezierCurve} from '../bezier-curve';
|
import {BezierCurve, isBezierCurve} from '../bezier-curve';
|
||||||
import {Vector} from '../vector';
|
import {Vector} from '../vector';
|
||||||
import {CSSImageType, CSSURLImage, isLinearGradient, isRadialGradient} from '../../css/types/image';
|
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 {Cache} from '../../core/cache-storage';
|
||||||
import {calculateBackgroundRendering, getBackgroundValueForIndex} from '../background';
|
import {calculateBackgroundRendering, getBackgroundValueForIndex} from '../background';
|
||||||
import {isDimensionToken} from '../../css/syntax/parser';
|
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.path(parsePathForBorder(curvePoints, side));
|
||||||
this.ctx.fillStyle = asString(color);
|
this.ctx.fillStyle = asString(color);
|
||||||
this.ctx.fill();
|
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) {
|
async renderNodeBackgroundAndBorders(paint: ElementPaint) {
|
||||||
this.applyEffects(paint.effects, EffectTarget.BACKGROUND_BORDERS);
|
this.applyEffects(paint.effects, EffectTarget.BACKGROUND_BORDERS);
|
||||||
const styles = paint.container.styles;
|
const styles = paint.container.styles;
|
||||||
const hasBackground = !isTransparent(styles.backgroundColor) || styles.backgroundImage.length;
|
const hasBackground = !isTransparent(styles.backgroundColor) || styles.backgroundImage.length;
|
||||||
|
|
||||||
const borders = [
|
const borders = [
|
||||||
{style: styles.borderTopStyle, color: styles.borderTopColor},
|
{style: styles.borderTopStyle, color: styles.borderTopColor, width: styles.borderTopWidth},
|
||||||
{style: styles.borderRightStyle, color: styles.borderRightColor},
|
{style: styles.borderRightStyle, color: styles.borderRightColor, width: styles.borderRightWidth},
|
||||||
{style: styles.borderBottomStyle, color: styles.borderBottomColor},
|
{style: styles.borderBottomStyle, color: styles.borderBottomColor, width: styles.borderBottomWidth},
|
||||||
{style: styles.borderLeftStyle, color: styles.borderLeftColor}
|
{style: styles.borderLeftStyle, color: styles.borderLeftColor, width: styles.borderLeftWidth}
|
||||||
];
|
];
|
||||||
|
|
||||||
const backgroundPaintingArea = calculateBackgroundCurvedPaintingArea(
|
const backgroundPaintingArea = calculateBackgroundCurvedPaintingArea(
|
||||||
@ -705,13 +725,143 @@ export class CanvasRenderer {
|
|||||||
|
|
||||||
let side = 0;
|
let side = 0;
|
||||||
for (const border of borders) {
|
for (const border of borders) {
|
||||||
if (border.style !== BORDER_STYLE.NONE && !isTransparent(border.color)) {
|
if (border.style !== BORDER_STYLE.NONE && !isTransparent(border.color) && border.width > 0) {
|
||||||
await this.renderBorder(border.color, side, paint.curves);
|
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++;
|
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> {
|
async render(element: ElementContainer): Promise<HTMLCanvasElement> {
|
||||||
if (this.options.backgroundColor) {
|
if (this.options.backgroundColor) {
|
||||||
this.ctx.fillStyle = asString(this.options.backgroundColor);
|
this.ctx.fillStyle = asString(this.options.backgroundColor);
|
||||||
|
@ -23,10 +23,11 @@ const servers: Server[] = [];
|
|||||||
servers.push(screenshotApp.listen(8000));
|
servers.push(screenshotApp.listen(8000));
|
||||||
servers.push(corsApp.listen(8081));
|
servers.push(corsApp.listen(8081));
|
||||||
|
|
||||||
karmaTestRunner().then(() => {
|
karmaTestRunner()
|
||||||
servers.forEach(server => server.close());
|
.then(() => {
|
||||||
}).catch(e => {
|
servers.forEach(server => server.close());
|
||||||
console.error(e);
|
})
|
||||||
process.exit(1);
|
.catch(e => {
|
||||||
});
|
console.error(e);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user