mirror of
https://github.com/idrawjs/idraw
synced 2026-05-23 17:48:23 +00:00
feat: core implement svg render
This commit is contained in:
parent
7c728eec53
commit
4cf389e91c
10 changed files with 143 additions and 9 deletions
|
|
@ -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
|
||||
|
|
|
|||
58
packages/core/example/lib/data/svg.js
Normal file
58
packages/core/example/lib/data/svg.js
Normal file
|
|
@ -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: `<svg t="1622524780663" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8365" width="200" height="200"><path d="M881 442.4H519.7v148.5h206.4c-8.9 48-35.9 88.6-76.6 115.8-34.4 23-78.3 36.6-129.9 36.6-99.9 0-184.4-67.5-214.6-158.2-7.6-23-12-47.6-12-72.9s4.4-49.9 12-72.9c30.3-90.6 114.8-158.1 214.7-158.1 56.3 0 106.8 19.4 146.6 57.4l110-110.1c-66.5-62-153.2-100-256.6-100-149.9 0-279.6 86-342.7 211.4-26 51.8-40.8 110.4-40.8 172.4S151 632.8 177 684.6C240.1 810 369.8 896 519.7 896c103.6 0 190.4-34.4 253.8-93 72.5-66.8 114.4-165.2 114.4-282.1 0-27.2-2.4-53.3-6.9-78.5z" p-id="8366" fill="#1296db"></path></svg>`,
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'svg-002',
|
||||
x: 80,
|
||||
y: 80,
|
||||
w: 200,
|
||||
h: 120,
|
||||
// angle: 30,
|
||||
type: 'svg',
|
||||
desc: {
|
||||
svg: '<svg t="1622524813445" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8606" width="200" height="200"><path d="M852.6 367.6c16.3-36.9 32.1-90.7 32.1-131.8 0-109.1-119.5-147.6-314.5-57.9-161.4-10.8-316.8 110.5-355.6 279.7 46.3-52.3 117.4-123.4 183-151.7C316.1 378.3 246.7 470 194 565.6c-31.1 56.9-66 148.8-66 217.5 0 147.9 139.3 129.8 270.4 63 47.1 23.1 99.8 23.4 152.5 23.4 145.7 0 276.4-81.4 325.2-219H694.9c-78.8 132.9-295.2 79.5-295.2-71.2h493.2c9.6-65.4-2.5-143.6-40.3-211.7zM224.8 648.3c26.6 76.7 80.6 143.8 150.4 185-133.1 73.4-259.9 43.6-150.4-185z m174-163.3c3-82.7 75.4-142.3 156-142.3 80.1 0 153 59.6 156 142.3h-312z m276.8-281.4c32.1-15.4 72.8-33 108.8-33 47.1 0 81.4 32.6 81.4 80.6 0 30-11.1 73.5-21.9 101.8-39.3-63.5-98.9-122.4-168.3-149.4z" p-id="8607" fill="#2aa515"></path></svg>',
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'svg-003',
|
||||
x: 160,
|
||||
y: 160,
|
||||
w: 200,
|
||||
h: 200,
|
||||
type: 'svg',
|
||||
angle: 80,
|
||||
desc: {
|
||||
svg: '<svg t="1622524835512" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9094" width="200" height="200"><path d="M270.1 741.7c0 23.4 19.1 42.5 42.6 42.5h48.7v120.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V784.1h85v120.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V784.1h48.7c23.5 0 42.6-19.1 42.6-42.5V346.4h-486v395.3zM627.2 141.6l44.9-65c2.6-3.8 2-8.9-1.5-11.4-3.5-2.4-8.5-1.2-11.1 2.6l-46.6 67.6c-30.7-12.1-64.9-18.8-100.8-18.8-35.9 0-70.1 6.7-100.8 18.8l-46.6-67.5c-2.6-3.8-7.6-5.1-11.1-2.6-3.5 2.4-4.1 7.4-1.5 11.4l44.9 65c-71.4 33.2-121.4 96.1-127.8 169.6h486c-6.6-73.6-56.7-136.5-128-169.7zM409.5 244.1c-14.8 0-26.9-12-26.9-26.9 0-14.8 12-26.9 26.9-26.9 14.8 0 26.9 12 26.9 26.9-0.1 14.9-12.1 26.9-26.9 26.9z m208.4 0c-14.8 0-26.9-12-26.9-26.9 0-14.8 12-26.9 26.9-26.9 14.8 0 26.9 12 26.9 26.9-0.1 14.9-12.1 26.9-26.9 26.9zM841.3 344.8c-30.2 0-54.6 24.8-54.6 55.4v216.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V400.1c0.1-30.6-24.3-55.3-54.6-55.3zM182.7 344.8c-30.2 0-54.6 24.8-54.6 55.4v216.4c0 30.5 24.5 55.4 54.6 55.4 30.2 0 54.6-24.8 54.6-55.4V400.1c0-30.6-24.5-55.3-54.6-55.3z" p-id="9095" fill="#2aa515"></path></svg>',
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'svg-004',
|
||||
x: 400 - 10,
|
||||
y: 300 - 100,
|
||||
w: 200,
|
||||
h: 200,
|
||||
type: 'svg',
|
||||
desc: {
|
||||
svg: '<svg t="1622524892065" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9337" width="200" height="200"><path d="M511.6 76.3C264.3 76.2 64 276.4 64 523.5 64 718.9 189.3 885 363.8 946c23.5 5.9 19.9-10.8 19.9-22.2v-77.5c-135.7 15.9-141.2-73.9-150.3-88.9C215 726 171.5 718 184.5 703c30.9-15.9 62.4 4 98.9 57.9 26.4 39.1 77.9 32.5 104 26 5.7-23.5 17.9-44.5 34.7-60.8-140.6-25.2-199.2-111-199.2-213 0-49.5 16.3-95 48.3-131.7-20.4-60.5 1.9-112.3 4.9-120 58.1-5.2 118.5 41.6 123.2 45.3 33-8.9 70.7-13.6 112.9-13.6 42.4 0 80.2 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.3-43.9 2.9 7.7 24.7 58.3 5.5 118 32.4 36.8 48.9 82.7 48.9 132.3 0 102.2-59 188.1-200 212.9 23.5 23.2 38.1 55.4 38.1 91v112.5c0.8 9 0 17.9 15 17.9 177.1-59.7 304.6-227 304.6-424.1 0-247.2-200.4-447.3-447.5-447.3z" p-id="9338"></path></svg>',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default data;
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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<T extends keyof TypeElemDesc>(
|
|||
});
|
||||
}
|
||||
|
||||
function drawSVG<T extends keyof TypeElemDesc>(
|
||||
ctx: TypeContext,
|
||||
elem: TypeElement<T>,
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<keyof TypeElemDesc>): 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!')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
const { Image, Blob, FileReader } = window;
|
||||
|
||||
export function loadImage(src: string): Promise<HTMLImageElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -10,4 +10,41 @@ export function loadImage(src: string): Promise<HTMLImageElement> {
|
|||
img.onerror = reject;
|
||||
img.src = src;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function loadSVG(svg: string, opts?: { width: number, height: number }): Promise<HTMLImageElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// let style = '';
|
||||
// if (opts) {
|
||||
// style = `min-height: ${opts.height}px; min-width: ${opts.width}px`
|
||||
// }
|
||||
// const _svg = `
|
||||
// <svg xmlns="http://www.w3.org/2000/svg"
|
||||
// width="${opts?.width || ''}"
|
||||
// height="${opts?.height || ''}"
|
||||
// style="${style}" >
|
||||
// <foreignObject width="100%" height="100%">
|
||||
// ${svg}
|
||||
// </foreignObject>
|
||||
// </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<FileReader>) {
|
||||
const base64: string = event?.target?.result as string;
|
||||
image.onload = function() {
|
||||
resolve(image);
|
||||
}
|
||||
image.src = base64;
|
||||
};
|
||||
reader.onerror = function(err) {
|
||||
reject(err);
|
||||
};
|
||||
})
|
||||
}
|
||||
Loading…
Reference in a new issue