mobility-toolbox-js
Version:
Toolbox for JavaScript applications in the domains of mobility and logistics.
201 lines (200 loc) • 8.63 kB
JavaScript
import createCanvas from '../utils/createCanvas';
export const rotateCanvas = (canvas, rotation) => {
const ctx = canvas.getContext('2d');
ctx === null || ctx === void 0 ? void 0 : ctx.translate(canvas.width / 2, canvas.height / 2);
ctx === null || ctx === void 0 ? void 0 : ctx.rotate(rotation);
ctx === null || ctx === void 0 ? void 0 : ctx.translate(-canvas.width / 2, -canvas.height / 2);
};
const arrowCache = {};
export const getArrowCanvas = (arrowSize, fillColor, pixelRatio = 1) => {
const key = `${arrowSize.toString()},${fillColor},${pixelRatio}`;
if (!arrowCache[key]) {
// Create the arrow canvas
const padding = 0 * pixelRatio;
const canvas = createCanvas(arrowSize[0] * pixelRatio, arrowSize[1] * pixelRatio);
const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');
if (canvas && ctx) {
ctx.fillStyle = fillColor;
ctx.beginPath();
ctx.moveTo(padding, padding);
ctx.lineTo(canvas.width - padding, canvas.height / 2);
ctx.lineTo(padding, canvas.height - padding);
ctx.fill();
ctx.beginPath();
ctx.moveTo(padding, padding);
ctx.lineTo(canvas.width - padding, canvas.height / 2);
ctx.lineTo(padding, canvas.height - padding);
ctx.lineTo(padding, padding);
ctx.stroke();
}
arrowCache[key] = canvas;
}
return arrowCache[key];
};
const bufferArrowCache = {};
export const getBufferArrowCanvas = (width, height, fillColor, arrowSize, rotation = 0, pixelRatio = 1, margin = 0) => {
if (!arrowSize) {
return null;
}
const bufferKey = `${fillColor},${width},${height},${rotation},${pixelRatio},${margin}.${arrowSize.toString()}`;
if (!bufferArrowCache[bufferKey]) {
// Create a buffer canvas around the current vehicle to display properly the arrow
const arrowCanvas = getArrowCanvas(arrowSize, fillColor, pixelRatio);
if (arrowCanvas) {
const bufferCanvas = createCanvas(width + arrowCanvas.width * 2 + margin * 2, height + arrowCanvas.height * 2 + margin * 2);
if (bufferCanvas) {
const bufferCtx = bufferCanvas.getContext('2d');
rotateCanvas(bufferCanvas, -rotation);
bufferCtx === null || bufferCtx === void 0 ? void 0 : bufferCtx.drawImage(arrowCanvas, bufferCanvas.width - arrowCanvas.width, bufferCanvas.height / 2 - arrowCanvas.height / 2 - margin / 2, arrowCanvas.width, arrowCanvas.height);
}
bufferArrowCache[bufferKey] = bufferCanvas;
}
}
return bufferArrowCache[bufferKey];
};
const cacheDelayBg = {};
/**
* Draw circle delay background
*/
export const getDelayBgCanvas = (radius, color, pixelRatio = 1, blurWidth = 1) => {
const key = `${radius}, ${color}, ${blurWidth}, ${pixelRatio}`;
const padding = 1 * pixelRatio; // must be the same as circle padding
const blur = blurWidth * pixelRatio;
if (!cacheDelayBg[key]) {
const size = radius * 2 + padding * 2 + blur * 2 + padding * 2;
const canvas = createCanvas(size, size);
const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');
if (canvas && ctx) {
ctx.beginPath();
ctx.arc(size / 2, size / 2, radius + padding + blur, 0, 2 * Math.PI, false);
ctx.fillStyle = color;
ctx.filter = `blur(${blur}px)`;
ctx.fill();
cacheDelayBg[key] = canvas;
}
}
return cacheDelayBg[key];
};
const cacheCanvasTextSize = {};
export const getCanvasTextSize = (text, font, color, outlineColor, outlineWidth, pixelRatio) => {
const key = `${text}, ${font}, ${color}, ${outlineColor}, ${outlineWidth}, ${pixelRatio}`;
if (!cacheCanvasTextSize[key]) {
const canvas = createCanvas(300 * pixelRatio, 300 * pixelRatio);
const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');
if (canvas && ctx) {
// We calcuate the text size first
ctx.font = font;
ctx.textBaseline = 'hanging';
ctx.textAlign = 'left';
ctx.fillStyle = color;
ctx.strokeStyle = outlineColor;
ctx.lineWidth = outlineWidth;
ctx.strokeText(text, 0, 0);
ctx.fillText(text, 0, 0);
const textMetrics = ctx.measureText(text);
const size = {
height: textMetrics.fontBoundingBoxAscent +
textMetrics.fontBoundingBoxDescent,
width: textMetrics.width,
};
cacheCanvasTextSize[key] = size;
}
}
return cacheCanvasTextSize[key];
};
const cacheDelayText = {};
/**
* Draw delay text
*/
export const getDelayTextCanvas = (text, fontSize, font, color, outlineColor = '#000', pixelRatio = 1) => {
const key = `${text}, ${font}, ${color}, ${outlineColor}, ${pixelRatio}`;
const padding = 2 * pixelRatio;
const lineWidth = 1.5 * pixelRatio;
if (!cacheDelayText[key]) {
const textSize = getCanvasTextSize(text, font, color, outlineColor, lineWidth, pixelRatio);
if ((textSize === null || textSize === void 0 ? void 0 : textSize.width) && (textSize === null || textSize === void 0 ? void 0 : textSize.height)) {
const canvas = createCanvas(textSize.width + padding * 2, textSize.height + padding * 2);
const ctx = canvas === null || canvas === void 0 ? void 0 : canvas.getContext('2d');
if (canvas && ctx) {
// We calcuate the text size first
ctx.font = font;
ctx.fillStyle = color;
ctx.lineWidth = lineWidth;
ctx.strokeStyle = outlineColor;
ctx.textAlign = 'left';
ctx.textBaseline = 'ideographic';
ctx.strokeText(text, padding, canvas.height - padding);
ctx.fillText(text, padding, canvas.height - padding);
cacheDelayText[key] = canvas;
}
}
}
return cacheDelayText[key];
};
const cacheCircle = {};
/**
* Draw colored circle with black border
*/
export const getCircleCanvas = (radius, color, hasStroke, hasDash, pixelRatio) => {
const key = `${radius}, ${color}, ${hasStroke}, ${hasDash}, ${pixelRatio}`;
const padding = 1 * pixelRatio;
const lineWidth = hasStroke ? 1 * pixelRatio : 0;
const lineDash = hasDash ? [5 * pixelRatio, 3 * pixelRatio] : null;
if (!cacheCircle[key]) {
const canvas = createCanvas(radius * 2 + padding * 2, radius * 2 + padding * 2);
if (canvas) {
const ctx = canvas.getContext('2d');
if (!ctx) {
return null;
}
ctx.fillStyle = color;
ctx.lineWidth = lineWidth;
ctx.strokeStyle = '#000000';
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, radius, 0, 2 * Math.PI, false);
ctx.fill();
if (lineDash) {
ctx.setLineDash(lineDash);
}
ctx.stroke();
cacheCircle[key] = canvas;
}
}
return cacheCircle[key];
};
const cacheText = {};
/**
* Draw text in the circle
*/
export const getTextCanvas = (text, radius, textSize, fillColor, strokeColor, hasStroke, pixelRatio, font) => {
const key = `${text}, ${radius}, ${textSize}, ${fillColor},${strokeColor}, ${hasStroke}, ${pixelRatio}`;
if (!cacheText[key]) {
const canvas = createCanvas(radius * 2, radius * 2);
if (canvas) {
const ctx = canvas.getContext('2d');
if (!ctx) {
return null;
}
// Draw a stroke to the text only if a provider provides realtime but we don't use it.
if (hasStroke) {
ctx.save();
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.font = font;
ctx.strokeStyle = strokeColor;
ctx.strokeText(text, radius, radius);
ctx.restore();
}
// Draw a text
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillStyle = fillColor;
ctx.font = font;
ctx.strokeStyle = strokeColor;
ctx.strokeText(text, radius, radius);
ctx.fillText(text, radius, radius);
cacheText[key] = canvas;
}
}
return cacheText[key];
};