page-flip
Version:
Powerful, simple and flexible JS Library for creating realistic and beautiful page turning effect
168 lines (121 loc) • 5.7 kB
text/typescript
import { Orientation, Render } from './Render';
import { PageFlip } from '../PageFlip';
import { FlipDirection } from '../Flip/Flip';
import { PageOrientation } from '../Page/Page';
import { FlipSetting } from '../Settings';
/**
* Class responsible for rendering the Canvas book
*/
export class CanvasRender extends Render {
private readonly canvas: HTMLCanvasElement;
private readonly ctx: CanvasRenderingContext2D;
constructor(app: PageFlip, setting: FlipSetting, inCanvas: HTMLCanvasElement) {
super(app, setting);
this.canvas = inCanvas;
this.ctx = inCanvas.getContext('2d');
}
public getContext(): CanvasRenderingContext2D {
return this.ctx;
}
public reload(): void {
//
}
protected drawFrame(): void {
this.clear();
if (this.orientation !== Orientation.PORTRAIT)
if (this.leftPage != null) this.leftPage.simpleDraw(PageOrientation.LEFT);
if (this.rightPage != null) this.rightPage.simpleDraw(PageOrientation.RIGHT);
if (this.bottomPage != null) this.bottomPage.draw();
this.drawBookShadow();
if (this.flippingPage != null) this.flippingPage.draw();
if (this.shadow != null) {
this.drawOuterShadow();
this.drawInnerShadow();
}
const rect = this.getRect();
if (this.orientation === Orientation.PORTRAIT) {
this.ctx.beginPath();
this.ctx.rect(rect.left + rect.pageWidth, rect.top, rect.width, rect.height);
this.ctx.clip();
}
}
private drawBookShadow(): void {
const rect = this.getRect();
this.ctx.save();
this.ctx.beginPath();
const shadowSize = rect.width / 20;
this.ctx.rect(rect.left, rect.top, rect.width, rect.height);
const shadowPos = { x: rect.left + rect.width / 2 - shadowSize / 2, y: 0 };
this.ctx.translate(shadowPos.x, shadowPos.y);
const outerGradient = this.ctx.createLinearGradient(0, 0, shadowSize, 0);
outerGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
outerGradient.addColorStop(0.4, 'rgba(0, 0, 0, 0.2)');
outerGradient.addColorStop(0.49, 'rgba(0, 0, 0, 0.1)');
outerGradient.addColorStop(0.5, 'rgba(0, 0, 0, 0.5)');
outerGradient.addColorStop(0.51, 'rgba(0, 0, 0, 0.4)');
outerGradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
this.ctx.clip();
this.ctx.fillStyle = outerGradient;
this.ctx.fillRect(0, 0, shadowSize, rect.height * 2);
this.ctx.restore();
}
private drawOuterShadow(): void {
const rect = this.getRect();
this.ctx.save();
this.ctx.beginPath();
this.ctx.rect(rect.left, rect.top, rect.width, rect.height);
const shadowPos = this.convertToGlobal({ x: this.shadow.pos.x, y: this.shadow.pos.y });
this.ctx.translate(shadowPos.x, shadowPos.y);
this.ctx.rotate(Math.PI + this.shadow.angle + Math.PI / 2);
const outerGradient = this.ctx.createLinearGradient(0, 0, this.shadow.width, 0);
if (this.shadow.direction === FlipDirection.FORWARD) {
this.ctx.translate(0, -100);
outerGradient.addColorStop(0, 'rgba(0, 0, 0, ' + this.shadow.opacity + ')');
outerGradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
} else {
this.ctx.translate(-this.shadow.width, -100);
outerGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
outerGradient.addColorStop(1, 'rgba(0, 0, 0, ' + this.shadow.opacity + ')');
}
this.ctx.clip();
this.ctx.fillStyle = outerGradient;
this.ctx.fillRect(0, 0, this.shadow.width, rect.height * 2);
this.ctx.restore();
}
private drawInnerShadow(): void {
const rect = this.getRect();
this.ctx.save();
this.ctx.beginPath();
const shadowPos = this.convertToGlobal({ x: this.shadow.pos.x, y: this.shadow.pos.y });
const pageRect = this.convertRectToGlobal(this.pageRect);
this.ctx.moveTo(pageRect.topLeft.x, pageRect.topLeft.y);
this.ctx.lineTo(pageRect.topRight.x, pageRect.topRight.y);
this.ctx.lineTo(pageRect.bottomRight.x, pageRect.bottomRight.y);
this.ctx.lineTo(pageRect.bottomLeft.x, pageRect.bottomLeft.y);
this.ctx.translate(shadowPos.x, shadowPos.y);
this.ctx.rotate(Math.PI + this.shadow.angle + Math.PI / 2);
const isw = (this.shadow.width * 3) / 4;
const innerGradient = this.ctx.createLinearGradient(0, 0, isw, 0);
if (this.shadow.direction === FlipDirection.FORWARD) {
this.ctx.translate(-isw, -100);
innerGradient.addColorStop(1, 'rgba(0, 0, 0, ' + this.shadow.opacity + ')');
innerGradient.addColorStop(0.9, 'rgba(0, 0, 0, 0.05)');
innerGradient.addColorStop(0.7, 'rgba(0, 0, 0, ' + this.shadow.opacity + ')');
innerGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
} else {
this.ctx.translate(0, -100);
innerGradient.addColorStop(0, 'rgba(0, 0, 0, ' + this.shadow.opacity + ')');
innerGradient.addColorStop(0.1, 'rgba(0, 0, 0, 0.05)');
innerGradient.addColorStop(0.3, 'rgba(0, 0, 0, ' + this.shadow.opacity + ')');
innerGradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
}
this.ctx.clip();
this.ctx.fillStyle = innerGradient;
this.ctx.fillRect(0, 0, isw, rect.height * 2);
this.ctx.restore();
}
private clear(): void {
this.ctx.fillStyle = 'white';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
}