fix: @idraw/core update image/svg element

This commit is contained in:
chenshenhai 2021-06-21 12:38:57 +08:00
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View 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>

View 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>

View file

@ -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

View file

@ -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;

View file

@ -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 },
]