Compare commits

...

12 Commits

Author SHA1 Message Date
CI
99f105cb66 chore(release): 1.0.0-rc.4 2019-09-22 05:11:36 +00:00
7d3456b78c fix: null backgroundColor option as transparent (#2012) 2019-09-21 21:45:05 -07:00
00555cf1ef fix: nested z-index ordering (#2011)
* fix zindex bug

* test: add z-index reftest for #1978

* fix: z-index ordering early exit
2019-09-21 21:12:36 -07:00
eedb81ef9e fix: correctly render partial borders (fix #1920) (#2010) 2019-09-21 20:33:54 -07:00
d4b58960dc Update canvas-renderer.ts (#2004)
* Update canvas-renderer.ts

Fixed an issue were a page wouldn't render.

Line 581 (now 582) threw exception: "Uncaught (in promise) DOMException: Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The image argument is a canvas element with a width or height of 0."

* Update canvas-renderer.ts
2019-09-21 19:33:48 -07:00
ee3ca35636 add missing -ms-grid display property to support IE grid layouts (#1926) 2019-09-21 19:32:42 -07:00
9a63797aa7 docs: fix typo (#1864) 2019-06-17 21:24:34 -07:00
81dcf7b6be fix: zero size iframe rendering (#1863) 2019-06-17 21:23:45 -07:00
61f4819e02 feat: ignore unsupported image functions (#1873) 2019-06-17 21:22:05 -07:00
CI
86a650bfd5 chore(release): 1.0.0-rc.3 2019-05-30 05:31:15 +00:00
cbaecdca28 fix: stack exceeding for css tokenizer (#1862)
* fix: stack exceeding for css tokenizer

* fix: token string recursion
2019-05-29 22:26:51 -07:00
cae44a6f0a fix: typescript options type definition (#1861) 2019-05-29 21:11:50 -07:00
20 changed files with 245 additions and 99 deletions

View File

@ -2,6 +2,36 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
# [1.0.0-rc.4](https://github.com/niklasvh/html2canvas/compare/v1.0.0-rc.3...v1.0.0-rc.4) (2019-09-22)
### docs
* fix typo (#1864) ([9a63797aa7fb81454008745d2a1c069ca24339a4](https://github.com/niklasvh/html2canvas/commit/9a63797aa7fb81454008745d2a1c069ca24339a4)), closes [#1864](https://github.com/niklasvh/html2canvas/issues/1864)
### feat
* ignore unsupported image functions (#1873) ([61f4819e02102b112513d57b16ec7d37e989af20](https://github.com/niklasvh/html2canvas/commit/61f4819e02102b112513d57b16ec7d37e989af20)), closes [#1873](https://github.com/niklasvh/html2canvas/issues/1873)
### fix
* correctly render partial borders (fix #1920) (#2010) ([eedb81ef9e114366a7e286e975659360cf9d0983](https://github.com/niklasvh/html2canvas/commit/eedb81ef9e114366a7e286e975659360cf9d0983)), closes [#1920](https://github.com/niklasvh/html2canvas/issues/1920) [#2010](https://github.com/niklasvh/html2canvas/issues/2010)
* nested z-index ordering (#2011) ([00555cf1efddfed5877811d8a03a326f9943ab06](https://github.com/niklasvh/html2canvas/commit/00555cf1efddfed5877811d8a03a326f9943ab06)), closes [#2011](https://github.com/niklasvh/html2canvas/issues/2011) [#1978](https://github.com/niklasvh/html2canvas/issues/1978)
* null backgroundColor option as transparent (#2012) ([7d3456b78c37e7333db087601805b32ec7ca0253](https://github.com/niklasvh/html2canvas/commit/7d3456b78c37e7333db087601805b32ec7ca0253)), closes [#2012](https://github.com/niklasvh/html2canvas/issues/2012)
* zero size iframe rendering (#1863) ([81dcf7b6be66920260a60908aa4b86e7530f6e17](https://github.com/niklasvh/html2canvas/commit/81dcf7b6be66920260a60908aa4b86e7530f6e17)), closes [#1863](https://github.com/niklasvh/html2canvas/issues/1863)
# [1.0.0-rc.3](https://github.com/niklasvh/html2canvas/compare/v1.0.0-rc.2...v1.0.0-rc.3) (2019-05-30)
### fix
* stack exceeding for css tokenizer (#1862) ([cbaecdca28cfaf9bd854e1b0c005cc8058208b36](https://github.com/niklasvh/html2canvas/commit/cbaecdca28cfaf9bd854e1b0c005cc8058208b36)), closes [#1862](https://github.com/niklasvh/html2canvas/issues/1862)
* typescript options type definition (#1861) ([cae44a6f0a6649bd8a7c4250a20792bb5c2e5b42](https://github.com/niklasvh/html2canvas/commit/cae44a6f0a6649bd8a7c4250a20792bb5c2e5b42)), closes [#1861](https://github.com/niklasvh/html2canvas/issues/1861)
# [1.0.0-rc.2](https://github.com/niklasvh/html2canvas/compare/v1.0.0-rc.1...v1.0.0-rc.2) (2019-05-29)

View File

@ -42,7 +42,7 @@ support [older browsers](http://caniuse.com/#search=promise) that do not nativel
To render an `element` with html2canvas, simply call:
` html2canvas(element[, options]);`
The function returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) containing the `<canvas>` element. Simply add a promise fullfillment handler to the promise using `then`:
The function returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) containing the `<canvas>` element. Simply add a promise fulfillment handler to the promise using `then`:
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "html2canvas",
"version": "1.0.0-rc.2",
"version": "1.0.0-rc.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -6,7 +6,7 @@
"module": "dist/html2canvas.esm.js",
"typings": "dist/types/index.d.ts",
"browser": "dist/html2canvas.js",
"version": "1.0.0-rc.2",
"version": "1.0.0-rc.4",
"author": {
"name": "Niklas von Hertzen",
"email": "niklasvh@gmail.com",

View File

@ -61,7 +61,7 @@ export class CacheStorage {
}
}
interface ResourceOptions {
export interface ResourceOptions {
imageTimeout: number;
useCORS: boolean;
allowTaint: boolean;

View File

@ -1,7 +1,7 @@
import {TokenType} from '../syntax/tokenizer';
import {ICSSImage, image} from '../types/image';
import {ICSSImage, image, isSupportedImage} from '../types/image';
import {IPropertyListDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor';
import {CSSValue, nonFunctionArgSeperator} from '../syntax/parser';
import {CSSValue, nonFunctionArgSeparator} from '../syntax/parser';
export const backgroundImage: IPropertyListDescriptor<ICSSImage[]> = {
name: 'background-image',
@ -19,6 +19,6 @@ export const backgroundImage: IPropertyListDescriptor<ICSSImage[]> = {
return [];
}
return tokens.filter(nonFunctionArgSeperator).map(image.parse);
return tokens.filter(value => nonFunctionArgSeparator(value) && isSupportedImage(value)).map(image.parse);
}
};

View File

@ -65,6 +65,7 @@ const parseDisplayValue = (display: string): Display => {
case '-webkit-flex':
return DISPLAY.FLEX;
case 'grid':
case '-ms-grid':
return DISPLAY.GRID;
case 'ruby':
return DISPLAY.RUBY;

View File

@ -149,7 +149,7 @@ export const isIdentWithValue = (token: CSSValue, value: string): boolean =>
isIdentToken(token) && token.value === value;
export const nonWhiteSpace = (token: CSSValue) => token.type !== TokenType.WHITESPACE_TOKEN;
export const nonFunctionArgSeperator = (token: CSSValue) =>
export const nonFunctionArgSeparator = (token: CSSValue) =>
token.type !== TokenType.WHITESPACE_TOKEN && token.type !== TokenType.COMMA_TOKEN;
export const parseFunctionArgs = (tokens: CSSValue[]): CSSValue[][] => {

View File

@ -316,7 +316,7 @@ export class Tokenizer {
}
write(chunk: string) {
this._value.push(...toCodePoints(chunk));
this._value = this._value.concat(toCodePoints(chunk));
}
read(): CSSToken[] {
@ -370,7 +370,6 @@ export class Tokenizer {
return this.consumeNumericToken();
}
break;
break;
case COMMA:
return COMMA_TOKEN;
case HYPHEN_MINUS:
@ -472,7 +471,6 @@ export class Tokenizer {
}
this.reconsumeCodePoint(codePoint);
return this.consumeIdentLikeToken();
break;
case VERTICAL_LINE:
if (this.peekCodePoint(0) === EQUALS_SIGN) {
this.consumeCodePoint();
@ -655,32 +653,51 @@ export class Tokenizer {
}
}
private consumeStringSlice(count: number): string {
const SLICE_STACK_SIZE = 60000;
let value = '';
while (count > 0) {
const amount = Math.min(SLICE_STACK_SIZE, count);
value += fromCodePoint(...this._value.splice(0, amount));
count -= amount;
}
this._value.shift();
return value;
}
private consumeStringToken(endingCodePoint: number): StringValueToken | Token {
let value = '';
let i = 0;
do {
const codePoint = this.consumeCodePoint();
if (codePoint === EOF || codePoint === endingCodePoint) {
const codePoint = this._value[i];
if (codePoint === EOF || codePoint === undefined || codePoint === endingCodePoint) {
value += this.consumeStringSlice(i);
return {type: TokenType.STRING_TOKEN, value};
}
if (codePoint === LINE_FEED) {
this.reconsumeCodePoint(codePoint);
this._value.splice(0, i);
return BAD_STRING_TOKEN;
}
if (codePoint === REVERSE_SOLIDUS) {
const next = this.peekCodePoint(0);
if (next !== EOF) {
const next = this._value[i + 1];
if (next !== EOF && next !== undefined) {
if (next === LINE_FEED) {
this.consumeCodePoint();
value += this.consumeStringSlice(i);
i = -1;
this._value.shift();
} else if (isValidEscape(codePoint, next)) {
value += this.consumeStringSlice(i);
value += fromCodePoint(this.consumeEscapedCodePoint());
i = -1;
}
}
} else {
value += fromCodePoint(codePoint);
}
i++;
} while (true);
}

View File

@ -1,4 +1,4 @@
import {CSSValue, nonFunctionArgSeperator} from '../syntax/parser';
import {CSSValue, nonFunctionArgSeparator} from '../syntax/parser';
import {TokenType} from '../syntax/tokenizer';
import {ITypeDescriptor} from '../ITypeDescriptor';
import {angle, deg} from './angle';
@ -86,7 +86,7 @@ const getTokenColorValue = (token: CSSValue, i: number): number => {
};
const rgb = (args: CSSValue[]): number => {
const tokens = args.filter(nonFunctionArgSeperator);
const tokens = args.filter(nonFunctionArgSeparator);
if (tokens.length === 3) {
const [r, g, b] = tokens.map(getTokenColorValue);
@ -121,7 +121,7 @@ function hue2rgb(t1: number, t2: number, hue: number): number {
}
const hsl = (args: CSSValue[]): number => {
const tokens = args.filter(nonFunctionArgSeperator);
const tokens = args.filter(nonFunctionArgSeparator);
const [hue, saturation, lightness, alpha] = tokens;
const h = (hue.type === TokenType.NUMBER_TOKEN ? deg(hue.number) : angle.parse(hue)) / (Math.PI * 2);

View File

@ -1,4 +1,4 @@
import {CSSValue, isIdentToken, isNumberToken, nonFunctionArgSeperator, parseFunctionArgs} from '../../syntax/parser';
import {CSSValue, isIdentToken, isNumberToken, nonFunctionArgSeparator, parseFunctionArgs} from '../../syntax/parser';
import {
CSSImageType,
CSSLinearGradientImage,
@ -40,7 +40,7 @@ export const webkitGradient = (tokens: CSSValue[]): CSSLinearGradientImage | CSS
const color = colorType.parse(firstToken.values[0]);
stops.push({stop: HUNDRED_PERCENT, color});
} else if (firstToken.name === 'color-stop') {
const values = firstToken.values.filter(nonFunctionArgSeperator);
const values = firstToken.values.filter(nonFunctionArgSeparator);
if (values.length === 2) {
const color = colorType.parse(values[1]);
const stop = values[0];

View File

@ -98,9 +98,11 @@ export const image: ITypeDescriptor<ICSSImage> = {
}
};
const SUPPORTED_IMAGE_FUNCTIONS: {
[key: string]: (args: CSSValue[]) => ICSSImage;
} = {
export function isSupportedImage(value: CSSValue) {
return value.type !== TokenType.FUNCTION || SUPPORTED_IMAGE_FUNCTIONS[value.name];
}
const SUPPORTED_IMAGE_FUNCTIONS: Record<string, (args: CSSValue[]) => ICSSImage> = {
'linear-gradient': linearGradient,
'-moz-linear-gradient': prefixLinearGradient,
'-ms-linear-gradient': prefixLinearGradient,

View File

@ -12,7 +12,7 @@ import {
isTextNode
} from './node-parser';
import {Logger} from '../core/logger';
import {isIdentToken, nonFunctionArgSeperator} from '../css/syntax/parser';
import {isIdentToken, nonFunctionArgSeparator} from '../css/syntax/parser';
import {TokenType} from '../css/syntax/tokenizer';
import {CounterState, createCounterText} from '../css/types/functions/counter';
import {LIST_STYLE_TYPE, listStyleType} from '../css/property-descriptors/list-style-type';
@ -355,7 +355,7 @@ export class DocumentCloner {
);
}
} else if (token.name === 'counter') {
const [counter, counterStyle] = token.values.filter(nonFunctionArgSeperator);
const [counter, counterStyle] = token.values.filter(nonFunctionArgSeparator);
if (counter && isIdentToken(counter)) {
const counterState = this.counters.getCounterValue(counter.value);
const counterType =
@ -368,7 +368,7 @@ export class DocumentCloner {
);
}
} else if (token.name === 'counters') {
const [counter, delim, counterStyle] = token.values.filter(nonFunctionArgSeperator);
const [counter, delim, counterStyle] = token.values.filter(nonFunctionArgSeparator);
if (counter && isIdentToken(counter)) {
const counterStates = this.counters.getCounterValues(counter.value);
const counterType =

View File

@ -15,8 +15,8 @@ export class IFrameElementContainer extends ElementContainer {
constructor(iframe: HTMLIFrameElement) {
super(iframe);
this.src = iframe.src;
this.width = parseInt(iframe.width, 10);
this.height = parseInt(iframe.height, 10);
this.width = parseInt(iframe.width, 10) || 0;
this.height = parseInt(iframe.height, 10) || 0;
this.backgroundColor = this.styles.backgroundColor;
try {
if (

View File

@ -4,25 +4,22 @@ import {Parser} from './css/syntax/parser';
import {CloneOptions, DocumentCloner} from './dom/document-cloner';
import {isBodyElement, isHTMLElement, parseTree} from './dom/node-parser';
import {Logger} from './core/logger';
import {CacheStorage} from './core/cache-storage';
import {CacheStorage, ResourceOptions} from './core/cache-storage';
import {CanvasRenderer, RenderOptions} from './render/canvas/canvas-renderer';
import {ForeignObjectRenderer} from './render/canvas/foreignobject-renderer';
export type Options = CloneOptions &
RenderOptions & {
allowTaint: boolean;
RenderOptions &
ResourceOptions & {
backgroundColor: string;
foreignObjectRendering: boolean;
imageTimeout: number;
logging: boolean;
proxy?: string;
removeContainer?: boolean;
useCORS: boolean;
};
const parseColor = (value: string): Color => color.parse(Parser.create(value).parseComponentValue());
const html2canvas = (element: HTMLElement, options: Options): Promise<HTMLCanvasElement> => {
const html2canvas = (element: HTMLElement, options: Partial<Options> = {}): Promise<HTMLCanvasElement> => {
return renderElement(element, options);
};
@ -30,7 +27,7 @@ export default html2canvas;
CacheStorage.setContext(window);
const renderElement = async (element: HTMLElement, opts: Options): Promise<HTMLCanvasElement> => {
const renderElement = async (element: HTMLElement, opts: Partial<Options>): Promise<HTMLCanvasElement> => {
const ownerDocument = element.ownerDocument;
if (!ownerDocument) {
@ -43,50 +40,43 @@ const renderElement = async (element: HTMLElement, opts: Options): Promise<HTMLC
throw new Error(`Document is not attached to a Window`);
}
const defaultOptions = {
const instanceName = (Math.round(Math.random() * 1000) + Date.now()).toString(16);
const {width, height, left, top} =
isBodyElement(element) || isHTMLElement(element) ? parseDocumentSize(ownerDocument) : parseBounds(element);
const defaultResourceOptions = {
allowTaint: false,
backgroundColor: '#ffffff',
imageTimeout: 15000,
logging: true,
proxy: undefined,
useCORS: false
};
const resourceOptions: ResourceOptions = {...defaultResourceOptions, ...opts};
const defaultOptions = {
backgroundColor: '#ffffff',
cache: opts.cache ? opts.cache : CacheStorage.create(instanceName, resourceOptions),
logging: true,
removeContainer: true,
foreignObjectRendering: false,
scale: defaultView.devicePixelRatio || 1,
useCORS: false,
windowWidth: defaultView.innerWidth,
windowHeight: defaultView.innerHeight,
scrollX: defaultView.pageXOffset,
scrollY: defaultView.pageYOffset
scrollY: defaultView.pageYOffset,
x: left,
y: top,
width: Math.ceil(width),
height: Math.ceil(height),
id: instanceName
};
const options: Options = {...defaultOptions, ...opts};
const options: Options = {...defaultOptions, ...resourceOptions, ...opts};
const windowBounds = new Bounds(options.scrollX, options.scrollY, options.windowWidth, options.windowHeight);
// http://www.w3.org/TR/css3-background/#special-backgrounds
const documentBackgroundColor = ownerDocument.documentElement
? parseColor(getComputedStyle(ownerDocument.documentElement).backgroundColor as string)
: COLORS.TRANSPARENT;
const bodyBackgroundColor = ownerDocument.body
? parseColor(getComputedStyle(ownerDocument.body).backgroundColor as string)
: COLORS.TRANSPARENT;
const backgroundColor =
element === ownerDocument.documentElement
? isTransparent(documentBackgroundColor)
? isTransparent(bodyBackgroundColor)
? options.backgroundColor
? parseColor(options.backgroundColor)
: null
: bodyBackgroundColor
: documentBackgroundColor
: options.backgroundColor
? parseColor(options.backgroundColor)
: null;
const instanceName = (Math.round(Math.random() * 1000) + Date.now()).toString(16);
Logger.create(instanceName);
const cache = CacheStorage.create(instanceName, options);
Logger.getInstance(instanceName).debug(`Starting document clone`);
const documentCloner = new DocumentCloner(element, {
id: instanceName,
@ -102,22 +92,37 @@ const renderElement = async (element: HTMLElement, opts: Options): Promise<HTMLC
const container = await documentCloner.toIFrame(ownerDocument, windowBounds);
const {width, height, left, top} =
isBodyElement(clonedElement) || isHTMLElement(clonedElement)
? parseDocumentSize(ownerDocument)
: parseBounds(clonedElement);
// http://www.w3.org/TR/css3-background/#special-backgrounds
const documentBackgroundColor = ownerDocument.documentElement
? parseColor(getComputedStyle(ownerDocument.documentElement).backgroundColor as string)
: COLORS.TRANSPARENT;
const bodyBackgroundColor = ownerDocument.body
? parseColor(getComputedStyle(ownerDocument.body).backgroundColor as string)
: COLORS.TRANSPARENT;
const bgColor = opts.backgroundColor;
const defaultBackgroundColor = typeof bgColor === 'string' ? parseColor(bgColor) : bgColor === null ? COLORS.TRANSPARENT : 0xffffffff;
const backgroundColor =
element === ownerDocument.documentElement
? isTransparent(documentBackgroundColor)
? isTransparent(bodyBackgroundColor)
? defaultBackgroundColor
: bodyBackgroundColor
: documentBackgroundColor
: defaultBackgroundColor;
const renderOptions = {
id: instanceName,
cache,
cache: options.cache,
backgroundColor,
scale: options.scale,
x: typeof options.x === 'number' ? options.x : left,
y: typeof options.y === 'number' ? options.y : top,
x: options.x,
y: options.y,
scrollX: options.scrollX,
scrollY: options.scrollY,
width: typeof options.width === 'number' ? options.width : Math.ceil(width),
height: typeof options.height === 'number' ? options.height : Math.ceil(height),
width: options.width,
height: options.height,
windowWidth: options.windowWidth,
windowHeight: options.windowHeight
};
@ -131,7 +136,7 @@ const renderElement = async (element: HTMLElement, opts: Options): Promise<HTMLC
} else {
Logger.getInstance(instanceName).debug(`Document cloned, using computed rendering`);
CacheStorage.attachInstance(cache);
CacheStorage.attachInstance(options.cache);
Logger.getInstance(instanceName).debug(`Starting DOM parsing`);
const root = parseTree(clonedElement);
CacheStorage.detachInstance();

View File

@ -39,11 +39,14 @@ import {SelectElementContainer} from '../../dom/elements/select-element-containe
import {IFrameElementContainer} from '../../dom/replaced-elements/iframe-element-container';
import {TextShadow} from '../../css/property-descriptors/text-shadow';
export type RenderConfigurations = RenderOptions & {
backgroundColor: Color | null;
};
export interface RenderOptions {
id: string;
scale: number;
canvas?: HTMLCanvasElement;
backgroundColor: Color | null;
x: number;
y: number;
scrollX: number;
@ -60,11 +63,11 @@ const MASK_OFFSET = 10000;
export class CanvasRenderer {
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
options: RenderOptions;
options: RenderConfigurations;
private readonly _activeEffects: IElementEffect[] = [];
private readonly fontMetrics: FontMetrics;
constructor(options: RenderOptions) {
constructor(options: RenderConfigurations) {
this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
this.options = options;
@ -303,17 +306,19 @@ export class CanvasRenderer {
});
const canvas = await iframeRenderer.render(container.tree);
this.ctx.drawImage(
canvas,
0,
0,
container.width,
container.width,
container.bounds.left,
container.bounds.top,
container.bounds.width,
container.bounds.height
);
if (container.width && container.height) {
this.ctx.drawImage(
canvas,
0,
0,
container.width,
container.height,
container.bounds.left,
container.bounds.top,
container.bounds.width,
container.bounds.height
);
}
}
if (container instanceof InputElementContainer) {
@ -573,8 +578,10 @@ export class CanvasRenderer {
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
const pattern = this.ctx.createPattern(canvas, 'repeat') as CanvasPattern;
this.renderRepeat(path, pattern, x, y);
if ((width > 0) && (height > 0)) {
const pattern = this.ctx.createPattern(canvas, 'repeat') as CanvasPattern;
this.renderRepeat(path, pattern, x, y);
}
} else if (isRadialGradient(backgroundImage)) {
const [path, left, top, width, height] = calculateBackgroundRendering(container, index, [
null,
@ -694,8 +701,9 @@ 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);
await this.renderBorder(border.color, side, paint.curves);
}
side++;
}
}

View File

@ -1,4 +1,4 @@
import {RenderOptions} from './canvas-renderer';
import {RenderConfigurations} from './canvas-renderer';
import {Logger} from '../../core/logger';
import {createForeignObjectSVG} from '../../core/features';
import {asString} from '../../css/types/color';
@ -6,9 +6,9 @@ import {asString} from '../../css/types/color';
export class ForeignObjectRenderer {
canvas: HTMLCanvasElement;
ctx: CanvasRenderingContext2D;
options: RenderOptions;
options: RenderConfigurations;
constructor(options: RenderOptions) {
constructor(options: RenderConfigurations) {
this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
this.options = options;

View File

@ -104,8 +104,11 @@ const parseStackTree = (
parentStack.negativeZIndex.some((current, i) => {
if (order > current.element.container.styles.zIndex.order) {
index = i;
return false;
} else if (index > 0) {
return true;
}
return false;
});
parentStack.negativeZIndex.splice(index, 0, stack);
@ -114,6 +117,8 @@ const parseStackTree = (
parentStack.positiveZIndex.some((current, i) => {
if (order > current.element.container.styles.zIndex.order) {
index = i + 1;
return false;
} else if (index > 0) {
return true;
}

View File

@ -40,6 +40,12 @@
border-bottom-width: 50px;
}
.box6 {
border-style: none solid none solid;
border-color: #807d32;
border-width: 50px;
}
html {
background: #3a84c3;
}
@ -51,5 +57,6 @@
<div class="box3">&nbsp;</div>
<div class="box4">&nbsp;</div>
<div class="box5">&nbsp;</div>
<div class="box6">&nbsp;</div>
</body>
</html>

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>z-index19</title>
<style>
.canvas-view {
display: flex;
flex-direction: row;
}
.main {
position: relative;
width: 500px;
height: 500px;
margin-right: 50px;
}
.div1 {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: red;
}
.div2 {
position: absolute;
z-index: 2;
top: 100px;
left: 100px;
bottom: 0;
right: 0;
background-color: green;
}
.div3 {
position: absolute;
z-index: 3;
top: 200px;
left: 200px;
bottom: 0;
right: 0;
background-color: blue;
}
.div4 {
position: absolute;
z-index: 4;
top: 300px;
left: 300px;
bottom: 0;
right: 0;
background-color: white;
}
</style>
<script type="text/javascript" src="../../test.js"></script>
</head>
<body>
<div class="canvas-view" id="my-home">
<div class="main" id="my-div">
<div class="div1"></div>
<div class="div2"></div>
<div class="div3"></div>
<div class="div4"></div>
</div>
</div>
</body>
</html>