feat: init core render

This commit is contained in:
chenshenhai 2021-05-26 14:23:30 +08:00
parent 53935a884b
commit d04cc215b4
12 changed files with 168 additions and 35 deletions

View file

@ -9,7 +9,8 @@
"init": "lerna bootstrap --npm-client=cnpm",
"clear": "rm -rf ./packages/*/dist/ & rm -rf ./packages/*/node_modules/",
"jest": "jest --config jest.config.js",
"test": "lerna bootstrap --no-ci && npm run build && npm run jest && npm run e2e"
"test": "lerna bootstrap --no-ci && npm run build && npm run jest && npm run e2e",
"serve": "http-server ./"
},
"devDependencies": {
"@babel/core": "^7.13.14",

View file

@ -9,6 +9,4 @@ const core = new Core(mount, {
devicePixelRatio: 4
});
core.setData(data);
core.draw();
console.log('hello world =', Core);
core.draw();

View file

@ -1,5 +1,6 @@
import { TypeData } from '@idraw/types';
import Board from '@idraw/board';
import Renderer from './lib/renderer';
type Options = {
width: number;
@ -12,31 +13,17 @@ class Core {
private _board: Board;
private _data: TypeData;
private _opts: Options;
private _renderer: Renderer;
constructor(mount: HTMLDivElement, opts: Options) {
this._data = { elements: [] };
this._opts = opts;
this._board = new Board(mount, this._opts);
this._renderer = new Renderer(this._board);
}
draw() {
const board = this._board;
const ctx = board.getContext();
const data = this.getData();
const { width, height } = this._opts;
board.clear();
ctx.clearRect(0, 0, width, height);
ctx.setFillStyle('#ffffff');
ctx.fillRect(0, 0, width, height);
data.elements.forEach(ele => {
// @ts-ignore
if (ele.type === 'rect' && typeof ele.desc.color === 'string') {
// @ts-ignore
ctx.setFillStyle(ele.desc.color);
}
ctx.fillRect(ele.x, ele.y, ele.w, ele.h);
});
board.draw();
this._renderer.render(this._data);
}
getData() {

View file

@ -0,0 +1,22 @@
import { TypeContext, TypeData, TypeElement, TypeElemDesc } from '@idraw/types';
export function drawContext(ctx: TypeContext, data: TypeData) {
for (let i = 0; i < data.elements.length; i++) {
const ele = data.elements[i];
switch (ele.type) {
case 'rect': {
drawRect<'rect'>(ctx, ele as TypeElement<'rect'>);
};
default: {
// nothing
}
}
}
}
function drawRect<T extends keyof TypeElemDesc>(ctx: TypeContext, ele: TypeElement<T>) {
const desc = ele.desc as TypeElemDesc['rect'];
ctx.setFillStyle(desc.color);
ctx.fillRect(ele.x, ele.y, ele.w, ele.h);
}

View file

@ -0,0 +1,21 @@
import { TypeContext, TypeData } from '@idraw/types';
import { drawContext } from './draw';
import Board from '@idraw/board';
export default class Renderer {
private _board: Board;
private _ctx: TypeContext;
private _data: TypeData = { elements: [] };
constructor(board: Board) {
this._board = board;
this._ctx = this._board.getContext();
}
render(data: TypeData) {
this._data = data;
drawContext(this._ctx, this._data);
this._board.draw();
}
}

View file

@ -0,0 +1,7 @@
export function toColorHexNum(color: string): number {
return parseInt(color.replace(/^\#/, '0x'));
}
export function toColorHexStr(color: number): string {
return '#' + color.toString(16);
}

View file

@ -0,0 +1,16 @@
type ImageType = 'image/jpeg' | 'image/png';
export function downloadImageFromCanvas (
canvas: HTMLCanvasElement,
opts: { filename: string, type: ImageType }
) {
const { filename, type = 'image/jpeg' } = opts;
const stream = canvas.toDataURL(type);
const downloadLink = document.createElement('a');
downloadLink.href = stream;
downloadLink.download = filename;
const downloadClickEvent = document.createEvent('MouseEvents');
downloadClickEvent.initEvent('click', true, false);
downloadLink.dispatchEvent(downloadClickEvent);
}

View file

@ -0,0 +1,22 @@
import { loadImage } from './loader';
import { delay, compose, throttle } from './time';
import { downloadImageFromCanvas } from './file';
import { toColorHexStr, toColorHexNum } from './color';
export default {
time: {
delay,
compose,
throttle,
},
loader: {
loadImage
},
file: {
downloadImageFromCanvas,
},
color: {
toColorHexStr,
toColorHexNum,
}
}

View file

@ -0,0 +1,13 @@
export function loadImage(src: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image;
img.onload = function() {
resolve(img);
};
img.onabort = reject;
img.onerror = reject;
img.src = src;
});
}

View file

@ -0,0 +1,44 @@
export function compose (middleware: Function[]) {
return function (context: any, next?: Function) {
// let index = -1;
return dispatch(0);
function dispatch (i: number): Promise<any> {
// index = i
let fn = middleware[i]
if (i === middleware.length && next) {
fn = next;
}
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
export function delay(time: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
})
}
export function throttle(fn: Function, timeout: number) {
let timer: any = -1;
return function(...args: any[]) {
if (timer > 0) {
return;
}
timer = setTimeout(() => {
fn(...args);
timer = -1;
}, timeout)
}
}

View file

@ -1,21 +1,12 @@
import { TypeElementsDesc } from './element';
import { TypeElemDesc, TypeElement } from './element';
type TypeDataElement<T extends keyof TypeElementsDesc> = {
uuid?: string;
x: number;
y: number;
w: number;
h: number;
type: T;
desc: TypeElementsDesc[T];
}
type TypeData = {
elements: TypeDataElement<keyof TypeElementsDesc>[]
elements: TypeElement<keyof TypeElemDesc>[]
selectedElements?: string[] // uuids
}
export {
TypeDataElement,
TypeData
}

View file

@ -1,6 +1,16 @@
import { TypePaintData } from './paint';
type TypeElementsDesc = {
type TypeElement<T extends keyof TypeElemDesc> = {
uuid?: string;
x: number;
y: number;
w: number;
h: number;
type: T;
desc: TypeElemDesc[T];
}
type TypeElemDesc = {
text: TypeElemDescText,
rect: TypeElemDescRect,
circle: TypeElemDescCircle,
@ -33,5 +43,6 @@ export {
TypeElemDescText,
TypeElemDescRect,
TypeElemDescCircle,
TypeElementsDesc,
TypeElemDesc,
TypeElement,
}