Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: console error exporting PNG/PDF in playground #3205

Merged
merged 22 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4f6c63d
fix: the error of importing notion database
zuoxiaodong0815 Jun 1, 2023
fad2857
fix: the error of importing notion database
zuoxiaodong0815 Jun 1, 2023
d72b00e
fix: the error of importing notion database
zuoxiaodong0815 Jun 1, 2023
cbb3079
fix: the error of importing notion database
zuoxiaodong0815 Jun 1, 2023
5c9ffd4
Merge branch 'master' into master
zuoxiaodong0815 Jun 1, 2023
32af742
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 2, 2023
84d59bd
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 7, 2023
fa50f90
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 12, 2023
3ee32c1
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 12, 2023
6bce1e1
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 14, 2023
5e97c18
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 15, 2023
979fc4a
Merge branch 'toeverything:master' into master
zuoxiaodong0815 Jun 19, 2023
5793bd1
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 20, 2023
17c72b0
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 22, 2023
701f0d9
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 25, 2023
3e1a003
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 25, 2023
045bc84
Merge branch 'master' into feat/exportfile
zuoxiaodong0815 Jun 25, 2023
826bcf0
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 25, 2023
1a06c09
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 26, 2023
b35f6f1
fix: console error exporting PNG/PDF in playground
zuoxiaodong0815 Jun 26, 2023
05ac07b
refactor: private methods
doodlewind Jun 26, 2023
c8e0484
style: naming
doodlewind Jun 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 132 additions & 42 deletions packages/blocks/src/__internal__/content-parser/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { assertExists } from '@blocksuite/global/utils';
import type { IBound } from '@blocksuite/phasor';
import type { BaseBlockModel, Page } from '@blocksuite/store';
import { Slot } from '@blocksuite/store';
import { marked } from 'marked';

import { xywhArrayToObject } from '../..//page-block/edgeless/utils.js';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that something is wrong here.

import type { PageBlockModel } from '../../models.js';
import type { EdgelessPageBlockComponent } from '../../page-block/edgeless/edgeless-page-block.js';
import { getFileFromClipboard } from '../clipboard/utils/pure.js';
import {
getBlockElementById,
getEditorContainer,
getPageBlock,
isPageMode,
Expand Down Expand Up @@ -76,64 +79,149 @@ export class ContentParser {
);
}

public async transPageToCanvas(): Promise<HTMLCanvasElement | undefined> {
private async _checkReady() {
const promise = new Promise(resolve => {
let count = 0;
const checkReactRender = setInterval(async () => {
const root = this._page.root;
const pageBlock = root ? getPageBlock(root) : null;
const imageLoadingComponent = document.querySelector(
'affine-image-block-loading-card'
);
if (pageBlock && !imageLoadingComponent) {
clearInterval(checkReactRender);
resolve(true);
}
count++;
if (count > 10 * 60) {
clearInterval(checkReactRender);
resolve(false);
}
}, 100);
});
return await promise;
}

private async _edgelessToCanvas(
edgeless: EdgelessPageBlockComponent,
bound: IBound
): Promise<HTMLCanvasElement | undefined> {
const root = this._page.root;
if (!root) return;

const html2canvas = (await import('html2canvas')).default;
if (!(html2canvas instanceof Function)) return;

const container = document.querySelector(
'.affine-block-children-container'
);
if (!container) return;

const dpr = window.devicePixelRatio || 1;
const canvas = document.createElement('canvas');
canvas.width = (bound.w + 100) * dpr;
canvas.height = (bound.h + 100) * dpr;
const ctx = canvas.getContext('2d');
if (!ctx) return;
ctx.scale(dpr, dpr);

ctx.fillStyle = window.getComputedStyle(container).backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);

const html2canvasOption = {
ignoreElements: function (element: Element) {
if (
element.tagName === 'AFFINE-BLOCK-HUB' ||
element.tagName === 'EDGELESS-TOOLBAR' ||
element.classList.contains('dg')
) {
return true;
} else {
return false;
}
},
onclone: function (documentClone: Document, element: HTMLElement) {
// html2canvas can't support transform feature
element.style.setProperty('transform', 'none');
},
};

const nodeElements = edgeless.getSortedElementsByBound(bound);
for (const nodeElement of nodeElements) {
const blockElement = getBlockElementById(nodeElement.id)?.closest(
'.affine-edgeless-block-child'
);
const blockBound = xywhArrayToObject(nodeElement);
const canvasData = await html2canvas(
blockElement as HTMLElement,
html2canvasOption
);
ctx.drawImage(
canvasData,
blockBound.x - bound.x + 50,
blockBound.y - bound.y + 50,
blockBound.w,
blockBound.h
);
}

const surfaceCanvas = edgeless.surface.viewport.getCanvasByBound(bound);
ctx.drawImage(surfaceCanvas, 50, 50, bound.w, bound.h);

return canvas;
}

private async _docToCanvas(): Promise<HTMLCanvasElement | void> {
const editorContainer = getEditorContainer(this._page);
if (isPageMode(this._page)) {
const styleElement = document.createElement('style');
styleElement.textContent =
'editor-container,.affine-editor-container {height: auto;}';
editorContainer.appendChild(styleElement);
const pageContainer = editorContainer.querySelector(
'.affine-default-page-block-container'
);
if (!pageContainer) return;

const html2canvas = (await import('html2canvas')).default;
if (!(html2canvas instanceof Function)) return;

const html2canvasOption = {
ignoreElements: function (element: Element) {
if (
element.tagName === 'AFFINE-BLOCK-HUB' ||
element.tagName === 'EDGELESS-TOOLBAR' ||
element.classList.contains('dg')
) {
return true;
} else {
return false;
}
},
};

// todo check render and image
const data = await html2canvas(
pageContainer as HTMLElement,
html2canvasOption
);
return data;
}

const data = await html2canvas(editorContainer);
editorContainer.removeChild(styleElement);
return data;
private async _toCanvas(): Promise<HTMLCanvasElement | void> {
await this._checkReady();

if (isPageMode(this._page)) {
return await this._docToCanvas();
} else {
const styleElement = document.createElement('style');
const root = this._page.root;
if (!root) return;

const edgeless = getPageBlock(root) as EdgelessPageBlockComponent;
const bound = edgeless.getElementsBound();
assertExists(bound);
const { x, y, w, h } = bound;
styleElement.textContent = `
edgeless-toolbar {display: none;}
editor-container,.affine-editor-container {height: ${
h + 100
}px; width: ${w + 100}px}
`;
editorContainer.appendChild(styleElement);

const width = edgeless.surface.viewport.width;
const height = edgeless.surface.viewport.height;
edgeless.surface.viewport.setCenter(
x + width / 2 - 50,
y + height / 2 - 50
);
edgeless.surface.onResize();

// todo check render and image

const promise = new Promise(resolve => {
setTimeout(async () => {
const canvasData = await html2canvas(editorContainer);
resolve(canvasData);
}, 0);
});
const data = (await promise) as HTMLCanvasElement;
editorContainer.removeChild(styleElement);
return data;
return await this._edgelessToCanvas(edgeless, bound);
}
}

public async exportPng() {
const root = this._page.root;
if (!root) return;
const canvasImage = await this.transPageToCanvas();
const canvasImage = await this._toCanvas();
if (!canvasImage) {
return;
}
Expand All @@ -147,7 +235,7 @@ export class ContentParser {
public async exportPdf() {
const root = this._page.root;
if (!root) return;
const canvasImage = await this.transPageToCanvas();
const canvasImage = await this._toCanvas();
if (!canvasImage) {
return;
}
Expand All @@ -163,7 +251,9 @@ export class ContentParser {
0,
0,
canvasImage.width,
canvasImage.height
canvasImage.height,
'',
'FAST'
);
FileExporter.exportFile(
(root as PageBlockModel).title.toString() + '.pdf',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,12 @@ export class EdgelessPageBlockComponent
});
}

getSortedElementsByBound(bound: IBound) {
return this.sortedNotes.filter(element => {
return intersects(bound, xywhArrayToObject(element));
});
}

// Just update `index`, we don't change the order of the notes in the children.
reorderNotes = ({ elements, type }: ReorderingAction<Selectable>) => {
const updateIndexes = (keys: string[], elements: Selectable[]) => {
Expand Down
40 changes: 34 additions & 6 deletions packages/phasor/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export interface SurfaceViewport {

addOverlay(overlay: Overlay): void;
removeOverlay(overlay: Overlay): void;

getCanvasByBound(bound: IBound): HTMLCanvasElement;
}

/**
Expand Down Expand Up @@ -256,22 +258,33 @@ export class Renderer implements SurfaceViewport {
}

private _render() {
const { ctx, gridManager, viewportBounds, width, height, rc, zoom } = this;
const { ctx, viewportBounds, width, height, rc, zoom } = this;
const dpr = window.devicePixelRatio;

ctx.clearRect(0, 0, width * dpr, height * dpr);
ctx.save();

ctx.setTransform(zoom * dpr, 0, 0, zoom * dpr, 0, 0);

const elements = gridManager.search(viewportBounds);
this._renderByBound(ctx, rc, viewportBounds);
}

private _renderByBound(
ctx: CanvasRenderingContext2D | null,
rc: RoughCanvas,
bound: IBound
) {
if (!ctx) return;

const { gridManager } = this;
const elements = gridManager.search(bound);
for (const element of elements) {
const dx = element.x - viewportBounds.x;
const dy = element.y - viewportBounds.y;
const dx = element.x - bound.x;
const dy = element.y - bound.y;
ctx.save();
ctx.translate(dx, dy);
const localRecord = element.localRecord;
if (intersects(element, viewportBounds) && localRecord.display) {
if (intersects(element, bound) && localRecord.display) {
ctx.globalAlpha = localRecord.opacity;
element.render(ctx, rc);
}
Expand All @@ -281,14 +294,29 @@ export class Renderer implements SurfaceViewport {

for (const overlay of this._overlays) {
ctx.save();
ctx.translate(-viewportBounds.x, -viewportBounds.y);
ctx.translate(-bound.x, -bound.y);
overlay.render(ctx);
ctx.restore();
}

ctx.restore();
}

public getCanvasByBound(bound: IBound): HTMLCanvasElement {
const dpr = window.devicePixelRatio || 1;
const canvas = document.createElement('canvas');
canvas.width = bound.w * dpr;
canvas.height = bound.h * dpr;

const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
ctx.scale(dpr, dpr);

const rc = new RoughCanvas(canvas);
this._renderByBound(ctx, rc, bound);

return canvas;
}

public addOverlay(overlay: Overlay) {
this._overlays.add(overlay);
this._shouldUpdate = true;
Expand Down
Loading