import { inject, injectable } from 'inversify'; import { Layer } from '../layer'; import { Disposable, DisposableCollection } from '@gedit/utils'; import { domUtils } from '@gedit/utils/lib/browser'; import { ConflatableMessage, IMessageHandler, Message, MessageLoop, } from '@phosphor/messaging'; // import * as ReactDOM from 'react-dom'; import { createRoot } from 'react-dom/client'; import * as React from 'react'; import { PipelineEntitiesSelector } from './pipeline-entities-selector'; import { AbleManager, EntityManager } from '../../common'; import { PipelineEntitiesImpl } from './pipeline-entities'; export const FLUSH_LAYER_REQUEST = 'flush-layer-request'; let id = 0; export class FlushLayerMessage extends ConflatableMessage { constructor(readonly layer: Layer) { super(FLUSH_LAYER_REQUEST + '_layer' + id++); } } /** * pipeline渲染器 */ @injectable() export class PipelineRenderer implements Disposable, IMessageHandler { protected toDispose = new DisposableCollection(); readonly layers: Layer[] = []; protected forceUpdates: Set = new Set(); readonly layerDrawMap: Map void> = new Map(); readonly layerFlushMessages: Map = new Map(); readonly node = domUtils.createDivWithClass('gedit-playground-pipeline'); constructor( @inject(PipelineEntitiesSelector) protected readonly selector: PipelineEntitiesSelector, @inject(EntityManager) entityManager: EntityManager, @inject(AbleManager) ableManager: AbleManager ) { /** * entity修改触发layer更新 */ this.toDispose.push( entityManager.onEntityChanged((entityType: string) => { const layers = this.selector.entityLayerMap.get(entityType); if (layers) layers.forEach(layer => this.updateLayer(layer)); }) ); /** * able修改则触发layer更新 */ this.toDispose.push( ableManager.onAbleChanged((ableType: string) => { const layers = this.selector.ableLayerMap.get(ableType); if (layers) layers.forEach(layer => this.updateLayer(layer)); }) ); } addLayer(layer: Layer): void { this.layers.push(layer); this.toDispose.push(layer); this.layerFlushMessages.set(layer, new FlushLayerMessage(layer)); layer.pipelineNode = this.node; layer.pipelineLayers = this.layers; // Auto create node if (layer.draw && !layer.node) { layer.node = document.createElement('div'); } // 把layer加到父亲节点上 if (layer.node) { this.node.appendChild(layer.node); layer.node.classList.add('gedit-playground-layer'); } if (layer.draw) { const draw = layer.draw.bind(layer); this.layerDrawMap.set(layer, () => { const drawResult = draw(); if (!layer.rootReact) { layer.rootReact = createRoot(layer.node!); } if (drawResult) { // ReactDOM.render({drawResult}, layer.node!); layer.rootReact.render({drawResult}); } }); // 重载layer draw layer.draw = () => { this.updateLayer(layer, true); }; } } flush(): void { this.layers.forEach(layer => { this.updateLayer(layer); }); } ready(): void { this.layers.forEach(layer => { if (layer.onReady) layer.onReady(); }); } dispose(): void { this.toDispose.dispose(); this.node.remove(); } processMessage(msg: Message): void { if (msg instanceof FlushLayerMessage) { this.onFlushRequest(msg.layer); } } protected onFlushRequest(layer: Layer): void { if (this.toDispose.disposed) return; const result = this.selector.getEntities(layer); // 这里更新layer的entities (layer.entityBindedList as PipelineEntitiesImpl).load(result.entities); const draw = this.layerDrawMap.get(layer); // 只有修改或强制刷新才会刷新 if (draw && (result.changed || this.forceUpdates.has(layer))) { this.forceUpdates.delete(layer); try { draw(); } catch (e) { console.error(e); } } } /** * 1. PostMessage: 会将消息在nextTick执行 * 2. ConflatableMessage: 当多个消息进来会在下一个nextTick做合并 * 3. 图层相互隔离,即时一层挂了也不受影响 */ updateLayer(layer: Layer, forceUpdate?: boolean): void { if (forceUpdate) { this.forceUpdates.add(layer); } MessageLoop.postMessage(this, this.layerFlushMessages.get(layer)!); } }