mirror of
https://github.com/idrawjs/idraw
synced 2026-05-24 01:58:27 +00:00
fix: @idraw/core update image/svg element
This commit is contained in:
parent
e3574b149e
commit
cffe5c816c
8 changed files with 193 additions and 52 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 153 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
BIN
__tests__/snapshot/core/examples/test/update-element.html.jpg
Normal file
BIN
__tests__/snapshot/core/examples/test/update-element.html.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
51
packages/core/examples/test/update-element-later.html
Normal file
51
packages/core/examples/test/update-element-later.html
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<style>
|
||||
html,body { margin: 0; padding: 0; }
|
||||
#mount canvas {
|
||||
border-right: 1px solid #aaaaaa40;
|
||||
border-bottom: 1px solid #aaaaaa40;
|
||||
background-image:
|
||||
linear-gradient(#aaaaaa40 1px, transparent 0),
|
||||
linear-gradient(90deg, #aaaaaa40 1px, transparent 0),
|
||||
linear-gradient(#aaa 1px, transparent 0),
|
||||
linear-gradient(90deg, #aaa 1px, transparent 0);
|
||||
background-size: 10px 10px, 10px 10px, 50px 50px, 50px 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="mount"></div>
|
||||
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script src="./../../../util/dist/index.global.js"></script>
|
||||
<script type="module">
|
||||
import data from './../features/lib/data/image.js';
|
||||
const { Core, util } = window.iDraw;
|
||||
data.elements.forEach((elem, i) => {
|
||||
elem.uuid = `aaaaaaaa-aaaa-aaaa-aaaa-aa000000000${i}`;
|
||||
});
|
||||
const core = new Core(
|
||||
document.querySelector('#mount'), {
|
||||
width: 600,
|
||||
height: 400,
|
||||
contextWidth: 600,
|
||||
contextHeight: 400,
|
||||
devicePixelRatio: 4
|
||||
});
|
||||
core.initData(data);
|
||||
core.draw();
|
||||
|
||||
setTimeout(() => {
|
||||
data.elements[0].desc.src = `./../images/phone.png?v=${Date.now()}`;
|
||||
core.updateElement(data.elements[0]);
|
||||
core.draw();
|
||||
console.log('update ok!');
|
||||
}, 2000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
48
packages/core/examples/test/update-element.html
Normal file
48
packages/core/examples/test/update-element.html
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<html>
|
||||
<head>
|
||||
<style></style>
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
|
||||
<style>
|
||||
html,body { margin: 0; padding: 0; }
|
||||
#mount canvas {
|
||||
border-right: 1px solid #aaaaaa40;
|
||||
border-bottom: 1px solid #aaaaaa40;
|
||||
background-image:
|
||||
linear-gradient(#aaaaaa40 1px, transparent 0),
|
||||
linear-gradient(90deg, #aaaaaa40 1px, transparent 0),
|
||||
linear-gradient(#aaa 1px, transparent 0),
|
||||
linear-gradient(90deg, #aaa 1px, transparent 0);
|
||||
background-size: 10px 10px, 10px 10px, 50px 50px, 50px 50px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="mount"></div>
|
||||
|
||||
|
||||
<script src="./../../dist/index.global.js"></script>
|
||||
<script src="./../../../util/dist/index.global.js"></script>
|
||||
<script type="module">
|
||||
import data from './../features/lib/data/image.js';
|
||||
const { Core, util } = window.iDraw;
|
||||
data.elements.forEach((elem, i) => {
|
||||
elem.uuid = `aaaaaaaa-aaaa-aaaa-aaaa-aa000000000${i}`;
|
||||
});
|
||||
const core = new Core(
|
||||
document.querySelector('#mount'), {
|
||||
width: 600,
|
||||
height: 400,
|
||||
contextWidth: 600,
|
||||
contextHeight: 400,
|
||||
devicePixelRatio: 4
|
||||
});
|
||||
core.initData(data);
|
||||
core.draw();
|
||||
|
||||
data.elements[0].desc.src = `./../images/phone.png?v=${Date.now()}`;
|
||||
core.updateElement(data.elements[0]);
|
||||
console.log('update ok!');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -20,22 +20,34 @@ export default class Loader {
|
|||
|
||||
private _opts: Options;
|
||||
private _event: LoaderEvent;
|
||||
private _loadData: TypeLoadData = {};
|
||||
private _patternMap: {[uuid: string]: CanvasPattern} = {}
|
||||
private _uuidQueue: string[] = [];
|
||||
private _status: LoaderStatus = LoaderStatus.FREE
|
||||
private _currentLoadData: TypeLoadData = {};
|
||||
private _currentUUIDQueue: string[] = [];
|
||||
private _storageLoadData: TypeLoadData = {};
|
||||
private _status: LoaderStatus = LoaderStatus.FREE;
|
||||
|
||||
private _waitingLoadQueue: Array<{
|
||||
uuidQueue: string[],
|
||||
loadData: TypeLoadData,
|
||||
}> = [];
|
||||
|
||||
constructor(opts: Options) {
|
||||
this._opts = opts;
|
||||
this._event = new LoaderEvent();
|
||||
this._waitingLoadQueue = [];
|
||||
}
|
||||
|
||||
load(data: TypeData): void {
|
||||
const [uuidQueue, loadData] = this._resetLoadData(data);
|
||||
this._uuidQueue = uuidQueue;
|
||||
this._loadData = loadData;
|
||||
if (this._status === LoaderStatus.FREE) {
|
||||
if (this._status === LoaderStatus.FREE || this._status === LoaderStatus.COMPLETE) {
|
||||
this._currentUUIDQueue = uuidQueue;
|
||||
this._currentLoadData = loadData;
|
||||
this._loadTask();
|
||||
} else if (this._status === LoaderStatus.LOADING && uuidQueue.length > 0) {
|
||||
this._waitingLoadQueue.push({
|
||||
uuidQueue,
|
||||
loadData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,8 +70,8 @@ export default class Loader {
|
|||
}
|
||||
|
||||
getContent(uuid: string): null | HTMLImageElement | HTMLCanvasElement {
|
||||
if (this._loadData[uuid]?.status === 'loaded') {
|
||||
return this._loadData[uuid].content;
|
||||
if (this._storageLoadData[uuid]?.status === 'loaded') {
|
||||
return this._storageLoadData[uuid].content;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -75,7 +87,7 @@ export default class Loader {
|
|||
return this._patternMap[elem.uuid];
|
||||
}
|
||||
}
|
||||
const item = this._loadData[elem.uuid];
|
||||
const item = this._currentLoadData[elem.uuid];
|
||||
if (item?.status === 'loaded') {
|
||||
const board = this._opts.board;
|
||||
const tempCanvas = board.createCanvas();
|
||||
|
|
@ -93,27 +105,29 @@ export default class Loader {
|
|||
}
|
||||
|
||||
private _resetLoadData(data: TypeData): [string[], TypeLoadData] {
|
||||
const loadData: TypeLoadData = this._loadData;
|
||||
const loadData: TypeLoadData = {};
|
||||
const uuidQueue: string[] = [];
|
||||
|
||||
const storageLoadData = this._storageLoadData;
|
||||
|
||||
// add new load-data
|
||||
for (let i = data.elements.length - 1; i >= 0; i --) {
|
||||
const elem = data.elements[i];
|
||||
if (['image', 'svg',].includes(elem.type)) {
|
||||
if (!loadData[elem.uuid]) {
|
||||
if (!storageLoadData[elem.uuid]) {
|
||||
loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
uuidQueue.push(elem.uuid);
|
||||
} else {
|
||||
if (elem.type === 'image') {
|
||||
const _ele = elem as TypeElement<'image'>;
|
||||
if (_ele.desc.src !== loadData[elem.uuid].source) {
|
||||
loadData[elem.uuid].status = 'null';
|
||||
if (_ele.desc.src !== storageLoadData[elem.uuid].source) {
|
||||
loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
uuidQueue.push(elem.uuid);
|
||||
}
|
||||
} else if (elem.type === 'svg') {
|
||||
const _ele = elem as TypeElement<'svg'>;
|
||||
if (_ele.desc.svg !== loadData[elem.uuid].source) {
|
||||
loadData[elem.uuid].status = 'null';
|
||||
if (_ele.desc.svg !== storageLoadData[elem.uuid].source) {
|
||||
loadData[elem.uuid] = this._createEmptyLoadItem(elem);
|
||||
uuidQueue.push(elem.uuid);
|
||||
}
|
||||
}
|
||||
|
|
@ -121,13 +135,14 @@ export default class Loader {
|
|||
}
|
||||
}
|
||||
|
||||
// clear unuse load-data
|
||||
const uuids = Object.keys(loadData);
|
||||
data.elements.forEach((elem) => {
|
||||
if (uuids.includes(elem.uuid) !== true) {
|
||||
delete loadData[elem.uuid];
|
||||
}
|
||||
});
|
||||
// // clear unuse load-data
|
||||
// const uuids = Object.keys(currentLoadData);
|
||||
// data.elements.forEach((elem) => {
|
||||
// if (uuids.includes(elem.uuid) !== true) {
|
||||
// delete loadData[elem.uuid];
|
||||
// }
|
||||
// });
|
||||
|
||||
return [uuidQueue, loadData];
|
||||
}
|
||||
|
||||
|
|
@ -156,14 +171,23 @@ export default class Loader {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this._uuidQueue.length === 0) {
|
||||
this._status = LoaderStatus.COMPLETE;
|
||||
this._event.trigger('complete', undefined);
|
||||
return;
|
||||
if (this._currentUUIDQueue.length === 0) {
|
||||
if (this._waitingLoadQueue.length === 0) {
|
||||
this._status = LoaderStatus.COMPLETE;
|
||||
this._event.trigger('complete', undefined);
|
||||
return;
|
||||
} else {
|
||||
const waitingItem = this._waitingLoadQueue.shift();
|
||||
if (waitingItem) {
|
||||
const { uuidQueue, loadData } = waitingItem;
|
||||
this._currentLoadData = loadData;
|
||||
this._currentUUIDQueue = uuidQueue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { maxParallelNum } = this._opts;
|
||||
const uuids = this._uuidQueue.splice(0, maxParallelNum);
|
||||
const uuids = this._currentUUIDQueue.splice(0, maxParallelNum);
|
||||
const uuidMap: {[uuid: string]: number} = {};
|
||||
|
||||
uuids.forEach((url, i) => {
|
||||
|
|
@ -186,39 +210,57 @@ export default class Loader {
|
|||
}
|
||||
loadUUIDList.push(uuid);
|
||||
|
||||
this._loadElementSource(this._loadData[uuid]).then((image) => {
|
||||
this._loadElementSource(this._currentLoadData[uuid]).then((image) => {
|
||||
loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1);
|
||||
const status = _loadAction();
|
||||
this._loadData[uuid].status = 'loaded';
|
||||
this._loadData[uuid].content = image;
|
||||
|
||||
this._storageLoadData[uuid] = {
|
||||
type: this._currentLoadData[uuid].type,
|
||||
status: 'loaded',
|
||||
content: image,
|
||||
source: this._currentLoadData[uuid].source,
|
||||
elemW: this._currentLoadData[uuid].elemW,
|
||||
elemH: this._currentLoadData[uuid].elemH,
|
||||
}
|
||||
|
||||
if (loadUUIDList.length === 0 && uuids.length === 0 && status === true) {
|
||||
this._status = LoaderStatus.FREE;
|
||||
this._loadTask();
|
||||
}
|
||||
this._event.trigger('load', {
|
||||
type: this._loadData[uuid].type,
|
||||
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,
|
||||
type: this._storageLoadData[uuid].type,
|
||||
status: this._storageLoadData[uuid].status,
|
||||
content: this._storageLoadData[uuid].content,
|
||||
source: this._storageLoadData[uuid].source,
|
||||
elemW: this._storageLoadData[uuid].elemW,
|
||||
elemH: this._storageLoadData[uuid].elemH,
|
||||
});
|
||||
}).catch((err) => {
|
||||
|
||||
loadUUIDList.splice(loadUUIDList.indexOf(uuid), 1);
|
||||
const status = _loadAction();
|
||||
this._loadData[uuid].status = 'fail';
|
||||
this._loadData[uuid].error = err;
|
||||
|
||||
this._storageLoadData[uuid] = {
|
||||
type: this._currentLoadData[uuid].type,
|
||||
status: 'fail',
|
||||
content: null,
|
||||
error: err,
|
||||
source: this._currentLoadData[uuid].source,
|
||||
elemW: this._currentLoadData[uuid].elemW,
|
||||
elemH: this._currentLoadData[uuid].elemH,
|
||||
}
|
||||
|
||||
if (loadUUIDList.length === 0 && uuids.length === 0 && status === true) {
|
||||
this._status = LoaderStatus.FREE;
|
||||
this._loadTask();
|
||||
}
|
||||
this._event.trigger('error', {
|
||||
type: this._loadData[uuid].type,
|
||||
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,
|
||||
type: this._storageLoadData[uuid].type,
|
||||
status: this._storageLoadData[uuid].status,
|
||||
content: this._storageLoadData[uuid].content,
|
||||
source: this._storageLoadData[uuid].source,
|
||||
elemW: this._storageLoadData[uuid].elemW,
|
||||
elemH: this._storageLoadData[uuid].elemH,
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -231,10 +273,10 @@ export default class Loader {
|
|||
private async _loadElementSource(
|
||||
params: TypeLoadData[string]
|
||||
): Promise<HTMLImageElement> {
|
||||
if (params.type === 'image') {
|
||||
if (params && params.type === 'image') {
|
||||
const image = await loadImage(params.source);
|
||||
return image;
|
||||
} else if (params.type === 'svg') {
|
||||
} else if (params && params.type === 'svg') {
|
||||
const image = await loadSVG(
|
||||
params.source, {
|
||||
width: params.elemW, height: params.elemH
|
||||
|
|
|
|||
|
|
@ -26,12 +26,11 @@ export class Renderer {
|
|||
board: board,
|
||||
maxParallelNum: 6
|
||||
});
|
||||
// TODO
|
||||
this._loader.on('load', (res) => {
|
||||
// console.log('load: ', res);
|
||||
this._drawFrame();
|
||||
});
|
||||
this._loader.on('error', (res) => {
|
||||
// console.log('error: ', res);
|
||||
console.log('Loader Error: ', res);
|
||||
});
|
||||
this._loader.on('complete', (res) => {
|
||||
// console.log('complete: ', res);
|
||||
|
|
@ -44,14 +43,14 @@ export class Renderer {
|
|||
if (this._status !== DrawStatus.DRAWING) {
|
||||
this._status = DrawStatus.DRAWING;
|
||||
this._drawFrame();
|
||||
this._loader.load(data);
|
||||
}
|
||||
this._loader.load(data);
|
||||
}
|
||||
|
||||
private _drawFrame() {
|
||||
requestAnimationFrame(() => {
|
||||
const ctx = this._board.getContext();
|
||||
// console.log('------ render frame ------', this._loader.isComplete())
|
||||
console.log('------ render frame ------', this._loader.isComplete())
|
||||
|
||||
let item: QueueItem | undefined = this._queue[0];
|
||||
let isLastFrame = false;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ const pageList = [
|
|||
{ path: 'core/examples/test/scale-002.html', w: 600, h: 400, delay: 500 },
|
||||
{ path: 'core/examples/test/scale-003.html', w: 600, h: 400, delay: 500 },
|
||||
{ path: 'core/examples/test/reset-size.html', w: 300, h: 300, delay: 500 },
|
||||
|
||||
{ path: 'core/examples/test/update-element.html', w: 600, h: 400, delay: 500 },
|
||||
{ path: 'core/examples/test/update-element-later.html', w: 600, h: 400, delay: 2500 },
|
||||
// { path: 'core/examples/test.html', w: 600, h: 600, delay: 8000 },
|
||||
]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue