import { renderString } from 'nunjucks';
import ParserLog from '../../models/ParserLog';
/**
* Class to render component.
*/
class ComponentRenderer {
/**
* Default constructor.
* @param {DefaultData} pluginData - Plugin data storage.
* @param {object} viewport - D3 selection of the view port.
* @param {boolean} readOnly - Read only state.
*/
constructor(pluginData, viewport, readOnly) {
/**
* Plugin data storage.
* @type {DefaultData}
*/
this.pluginData = pluginData || null;
/**
* D3 selection of the view port.
* @type {Selection}
*/
this.viewport = viewport || null;
/**
* Read only state.
*/
this.readOnly = !!readOnly;
}
/**
* Return a model from a Component data and Nunjucks template.
* @param {Component} component - Component to render.
* @returns {string} - Rendered model.
*/
renderModel(component) {
return renderString(
this.pluginData.resources.models[component.definition.model],
this.getTemplateData(component),
);
}
/**
* Render nodes for each component inside context.
* @param {string} id - Id of current context.
*/
render(id) {
const context = this.viewport.select(`.${id}`);
context.select('.components').selectAll(`.component[depth="${context.datum().depth + 1}"]`)
.data(({ children }) => children || [])
.join('g')
.attr('class', ({ data }) => `${data.id} component ${data.definition.isContainer
? 'container' : ''}`)
.attr('depth', ({ data }) => this.pluginData.getComponentDepth(data.id) + 1)
.html(({ data }) => this.renderModel(data))
.filter(({ data, children }) => data.definition.isContainer && !(!children))
.each(({ data }) => this.render(data.id));
}
/**
* Get data for nunjucks templating.
* @param {Component} component - Component to render.
* @returns {object} Data for templating.
*/
getTemplateData(component) {
let numberOfErrors = 0;
let numberOfWarnings = 0;
component.getErrors().forEach(({ severity }) => {
if (severity === ParserLog.SEVERITY_WARNING) {
numberOfWarnings += 1;
} else if (severity === ParserLog.SEVERITY_ERROR) {
numberOfErrors += 1;
}
});
return {
...component,
drawOption: {
...component.drawOption,
x: component.drawOption.x || 0,
y: component.drawOption.y || 0,
width: component.drawOption.width || component.definition.width,
height: component.drawOption.height || component.definition.height,
},
isReadOnly: this.readOnly,
icon: this.pluginData.resources.icons[component.definition.icon],
hasError: numberOfErrors > 0,
hasWarning: numberOfWarnings > 0,
numberOfErrors,
numberOfWarnings,
hasX: !!component.drawOption.x,
hasY: !!component.drawOption.y,
isSelected: this.pluginData.scene.selection.includes(component.id),
getIcon: (name) => this.pluginData.resources.icons[name],
canHaveLink: this.pluginData.canHaveLink(component.definition.type),
getAttribute: (name) => component.attributes.find((attribute) => attribute.name === name),
};
}
}
export default ComponentRenderer;
Source