From 4cf389e91c83ab2ef43f1fe75fa900281c97304f Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Tue, 1 Jun 2021 15:15:56 +0800 Subject: [PATCH] feat: core implement svg render --- docs/features/core.md | 5 +- .../lib/{data-image.js => data/image.js} | 0 .../lib/{data-rect.js => data/rect.js} | 0 packages/core/example/lib/data/svg.js | 58 +++++++++++++++++++ packages/core/example/main.js | 5 +- packages/core/src/lib/draw.ts | 20 +++++++ packages/core/src/lib/loader-event.ts | 2 + packages/core/src/lib/loader.ts | 18 +++++- packages/util/src/index.ts | 5 +- packages/util/src/lib/loader.ts | 39 ++++++++++++- 10 files changed, 143 insertions(+), 9 deletions(-) rename packages/core/example/lib/{data-image.js => data/image.js} (100%) rename packages/core/example/lib/{data-rect.js => data/rect.js} (100%) create mode 100644 packages/core/example/lib/data/svg.js diff --git a/docs/features/core.md b/docs/features/core.md index 24287d4..a13ddf1 100644 --- a/docs/features/core.md +++ b/docs/features/core.md @@ -6,9 +6,10 @@ - [] Image load queue - [] Render data's elements - [] Text - - [] Rect + - [x] Rect - [] Circle - - [] Image + - [x] Image + - [] SVG - [] Write - [x] Drag elements - [x] Move elements' index diff --git a/packages/core/example/lib/data-image.js b/packages/core/example/lib/data/image.js similarity index 100% rename from packages/core/example/lib/data-image.js rename to packages/core/example/lib/data/image.js diff --git a/packages/core/example/lib/data-rect.js b/packages/core/example/lib/data/rect.js similarity index 100% rename from packages/core/example/lib/data-rect.js rename to packages/core/example/lib/data/rect.js diff --git a/packages/core/example/lib/data/svg.js b/packages/core/example/lib/data/svg.js new file mode 100644 index 0000000..02f29d6 --- /dev/null +++ b/packages/core/example/lib/data/svg.js @@ -0,0 +1,58 @@ + +const data = { + // bgColor: '#ffffff', + elements: [ + { + name: 'svg-001', + x: 10, + y: 10, + w: 200, + h: 100, + type: 'svg', + // angle: 30, + // angle: 0, + desc: { + svg: ``, + } + }, + { + name: 'svg-002', + x: 80, + y: 80, + w: 200, + h: 120, + // angle: 30, + type: 'svg', + desc: { + svg: '', + } + }, + { + name: 'svg-003', + x: 160, + y: 160, + w: 200, + h: 200, + type: 'svg', + angle: 80, + desc: { + svg: '', + } + }, + { + name: 'svg-004', + x: 400 - 10, + y: 300 - 100, + w: 200, + h: 200, + type: 'svg', + desc: { + svg: '', + } + } + ] +} + + + +export default data; \ No newline at end of file diff --git a/packages/core/example/main.js b/packages/core/example/main.js index 89f8803..f7758d4 100644 --- a/packages/core/example/main.js +++ b/packages/core/example/main.js @@ -1,5 +1,6 @@ -// import data from './lib/data-rect.js'; -import data from './lib/data-image.js'; +// import data from './lib/data/rect.js'; +// import data from './lib/data/image.js'; +import data from './lib/data/svg.js'; import { doScale } from './lib/scale.js'; import { doScroll } from './lib/scroll.js'; import { doElemens } from './lib/element.js'; diff --git a/packages/core/src/lib/draw.ts b/packages/core/src/lib/draw.ts index c23f4b7..10f504b 100644 --- a/packages/core/src/lib/draw.ts +++ b/packages/core/src/lib/draw.ts @@ -34,6 +34,9 @@ export function drawContext( case 'image': { drawImage<'image'>(ctx, elem as TypeElement<'image'>, loader); } + case 'svg': { + drawSVG<'svg'>(ctx, elem as TypeElement<'svg'>, loader); + } default: { // nothing } @@ -70,6 +73,23 @@ function drawImage( }); } +function drawSVG( + ctx: TypeContext, + elem: TypeElement, + loader: Loader, +) { + // const desc = elem.desc as TypeElemDesc['rect']; + const content = loader.getContent(elem.uuid); + rotateElement(ctx, elem, () => { + // ctx.setFillStyle(desc.color); + // ctx.fillRect(elem.x, elem.y, elem.w, elem.h); + if (content) { + // ctx.drawImage(content, 0, 0, elem.w, elem.h, elem.x, elem.y, elem.w, elem.h); + ctx.drawImage(content, elem.x, elem.y, elem.w, elem.h); + } + }); +} + function drawBgColor(ctx: TypeContext, color: string) { const size = ctx.getSize(); ctx.setFillStyle(color); diff --git a/packages/core/src/lib/loader-event.ts b/packages/core/src/lib/loader-event.ts index 918fb09..d41fbc2 100644 --- a/packages/core/src/lib/loader-event.ts +++ b/packages/core/src/lib/loader-event.ts @@ -5,6 +5,8 @@ export type TypeLoadData = { type: 'image' | 'svg', status: 'null' | 'loaded' | 'fail', content: null | HTMLImageElement | HTMLCanvasElement, + elemW: number; + elemH: number; source: string, error?: any, } diff --git a/packages/core/src/lib/loader.ts b/packages/core/src/lib/loader.ts index 6cd85d1..7a674e0 100644 --- a/packages/core/src/lib/loader.ts +++ b/packages/core/src/lib/loader.ts @@ -2,7 +2,7 @@ import { TypeData, TypeElement, TypeElemDesc } from '@idraw/types'; import util from '@idraw/util'; import { LoaderEvent, TypeLoadData, TypeLoaderEventArgMap } from './loader-event'; -const { loadImage } = util.loader; +const { loadImage, loadSVG } = util.loader; type Options = { maxParallelNum: number @@ -86,7 +86,7 @@ export default class Loader { private _createEmptyLoadItem(elem: TypeElement): TypeLoadData[string] { let source = ''; - let type: TypeLoadData[string]['type'] = 'image'; + let type: TypeLoadData[string]['type'] = elem.type as TypeLoadData[string]['type']; if (elem.type === 'image') { const _elem = elem as TypeElement<'image'>; source = _elem.desc.src || ''; @@ -99,6 +99,8 @@ export default class Loader { status: 'null', content: null, source, + elemW: elem.w, + elemH: elem.h, } } @@ -151,6 +153,8 @@ export default class Loader { status: this._loadData[uuid].status, content: this._loadData[uuid].content, source: this._loadData[uuid].source, + elemW: this._loadData[uuid].elemW, + elemH: this._loadData[uuid].elemH, }); }).catch((err) => { loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1); @@ -166,6 +170,8 @@ export default class Loader { status: this._loadData[uuid].status, content: this._loadData[uuid].content, source: this._loadData[uuid].source, + elemW: this._loadData[uuid].elemW, + elemH: this._loadData[uuid].elemH, }) }) @@ -181,6 +187,14 @@ export default class Loader { if (params.type === 'image') { const image = await loadImage(params.source); return image; + } else if (params.type === 'svg') { + const image = await loadSVG( + params.source, + { + width: params.elemW, height: params.elemH + } + ); + return image; } throw Error('Element\'s source is not support!') } diff --git a/packages/util/src/index.ts b/packages/util/src/index.ts index 8388193..b585c03 100644 --- a/packages/util/src/index.ts +++ b/packages/util/src/index.ts @@ -1,10 +1,10 @@ -import { loadImage } from './lib/loader'; import { delay, compose, throttle } from './lib/time'; import { downloadImageFromCanvas } from './lib/file'; import { toColorHexStr, toColorHexNum, isColorStr } from './lib/color'; import { createUUID } from './lib/uuid'; import { deepClone } from './lib/data'; import istype from './lib/istype'; +import { loadImage, loadSVG } from './lib/loader'; export default { time: { @@ -13,7 +13,8 @@ export default { throttle, }, loader: { - loadImage + loadImage, + loadSVG, }, file: { downloadImageFromCanvas, diff --git a/packages/util/src/lib/loader.ts b/packages/util/src/lib/loader.ts index 7eedec1..55769b4 100644 --- a/packages/util/src/lib/loader.ts +++ b/packages/util/src/lib/loader.ts @@ -1,4 +1,4 @@ - +const { Image, Blob, FileReader } = window; export function loadImage(src: string): Promise { return new Promise((resolve, reject) => { @@ -10,4 +10,41 @@ export function loadImage(src: string): Promise { img.onerror = reject; img.src = src; }); +} + + +export function loadSVG(svg: string, opts?: { width: number, height: number }): Promise { + return new Promise((resolve, reject) => { + // let style = ''; + // if (opts) { + // style = `min-height: ${opts.height}px; min-width: ${opts.width}px` + // } + // const _svg = ` + // + // + // ${svg} + // + // + // `; + + const _svg = svg; + + const image = new Image(); + const blob = new Blob([_svg], { type: 'image/svg+xml;charset=utf-8'}); + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onload = function (event: ProgressEvent) { + const base64: string = event?.target?.result as string; + image.onload = function() { + resolve(image); + } + image.src = base64; + }; + reader.onerror = function(err) { + reject(err); + }; + }) } \ No newline at end of file