@lightningjs/renderer
Version:
Lightning 3 Renderer
132 lines • 5.8 kB
JavaScript
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2025 Comcast Cable Communications Management, LLC.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { calcHeight, measureText } from './Utils.js';
import { normalizeCanvasColor } from '../../lib/colorCache.js';
const MAX_TEXTURE_DIMENSION = 4096;
export const draw = (canvas, context, renderInfo, linesOverride) => {
const fontSize = renderInfo.fontSize;
const lineHeight = renderInfo.lineHeight;
const precision = renderInfo.precision;
const lines = linesOverride?.lines || renderInfo.lines;
const lineWidths = linesOverride?.lineWidths || renderInfo.lineWidths;
const height = linesOverride !== undefined
? calcHeight(renderInfo.textBaseline, fontSize, lineHeight, linesOverride.lines.length, 0)
: renderInfo.height;
// Add extra margin to prevent issue with clipped text when scaling.
canvas.width = Math.min(Math.ceil(renderInfo.width + renderInfo.textRenderIssueMargin), MAX_TEXTURE_DIMENSION);
canvas.height = Math.min(Math.ceil(height), MAX_TEXTURE_DIMENSION);
// Canvas context has been reset.
context.font = `${renderInfo.fontStyle} ${fontSize}px ${renderInfo.fontFamily}`;
context.textBaseline = renderInfo.textBaseline;
if (fontSize >= 128) {
context.globalAlpha = 0.01;
context.fillRect(0, 0, 0.01, 0.01);
context.globalAlpha = 1.0;
}
if (renderInfo.cutSx || renderInfo.cutSy) {
context.translate(-renderInfo.cutSx, -renderInfo.cutSy);
}
let linePositionX;
let linePositionY;
const drawLines = [];
const metrics = renderInfo.metrics;
const ascenderPx = metrics ? metrics.ascender * fontSize : fontSize;
const bareLineHeightPx = metrics
? (metrics.ascender - metrics.descender) * fontSize
: fontSize;
for (let i = 0, n = lines.length; i < n; i++) {
linePositionX = i === 0 ? renderInfo.textIndent : 0;
linePositionY = i * lineHeight + ascenderPx;
if (renderInfo.verticalAlign == 'middle') {
linePositionY += (lineHeight - bareLineHeightPx) / 2;
}
else if (renderInfo.verticalAlign == 'bottom') {
linePositionY += lineHeight - bareLineHeightPx;
}
if (renderInfo.textAlign === 'right') {
linePositionX += renderInfo.innerWidth - lineWidths[i];
}
else if (renderInfo.textAlign === 'center') {
linePositionX += (renderInfo.innerWidth - lineWidths[i]) / 2;
}
linePositionX += renderInfo.paddingLeft;
drawLines.push({
text: lines[i],
x: linePositionX,
y: linePositionY,
w: lineWidths[i],
});
}
// Highlight
if (renderInfo.highlight) {
const color = renderInfo.highlightColor;
const hlHeight = renderInfo.highlightHeight * precision || fontSize * 1.5;
const offset = renderInfo.highlightOffset * precision;
const hlPaddingLeft = renderInfo.highlightPaddingLeft !== null
? renderInfo.highlightPaddingLeft * precision
: renderInfo.paddingLeft;
const hlPaddingRight = renderInfo.highlightPaddingRight !== null
? renderInfo.highlightPaddingRight * precision
: renderInfo.paddingRight;
context.fillStyle = normalizeCanvasColor(color);
for (let i = 0; i < drawLines.length; i++) {
const drawLine = drawLines[i];
context.fillRect(drawLine.x - hlPaddingLeft, drawLine.y - renderInfo.offsetY + offset, drawLine.w + hlPaddingRight + hlPaddingLeft, hlHeight);
}
}
// Text shadow
let prevShadowSettings = null;
if (renderInfo.shadow) {
prevShadowSettings = [
context.shadowColor,
context.shadowOffsetX,
context.shadowOffsetY,
context.shadowBlur,
];
context.shadowColor = normalizeCanvasColor(renderInfo.shadowColor);
context.shadowOffsetX = renderInfo.shadowOffsetX * precision;
context.shadowOffsetY = renderInfo.shadowOffsetY * precision;
context.shadowBlur = renderInfo.shadowBlur * precision;
}
context.fillStyle = normalizeCanvasColor(renderInfo.textColor);
for (let i = 0, n = drawLines.length; i < n; i++) {
const drawLine = drawLines[i];
if (renderInfo.letterSpacing === 0) {
context.fillText(drawLine.text, drawLine.x, drawLine.y);
}
else {
const textSplit = drawLine.text.split('');
let x = drawLine.x;
for (let i = 0, j = textSplit.length; i < j; i++) {
context.fillText(textSplit[i], x, drawLine.y);
x += measureText(context, textSplit[i], renderInfo.letterSpacing);
}
}
}
if (prevShadowSettings) {
context.shadowColor = prevShadowSettings[0];
context.shadowOffsetX = prevShadowSettings[1];
context.shadowOffsetY = prevShadowSettings[2];
context.shadowBlur = prevShadowSettings[3];
}
if (renderInfo.cutSx || renderInfo.cutSy) {
context.translate(renderInfo.cutSx, renderInfo.cutSy);
}
};
//# sourceMappingURL=draw.js.map