You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
frameColor = 'rgba(173, 216, 230, 0.8)', // Light blue for lines/borders
backgroundColor = 'rgba(0, 0, 20, 1)', // Very dark blue for background
labelColor = 'rgba(200, 220, 255, 0.9)', // Lighter blue/white for text
framePadding = 30, // Space between image and inner frame border
borderThickness = 5, // Thickness of the main inner frame border
outerMargin = 50, // Space for ticks and labels outside inner frame
gridLineColor = 'rgba(100, 100, 150, 0.3)', // Dimmed blue/purple for grid
showGrid = 1, // Number: 1 to show grid, 0 to hide
fontSize = 12, // Font size for labels
numRaIntervals = 10, // Number of intervals for Right Ascension (horizontal)
numDecIntervals = 8 // Number of intervals for Declination (vertical)
) {
// Ensure numerical parameters are numbers and have valid ranges
numRaIntervals = Math.max(1, Number(numRaIntervals));
numDecIntervals = Math.max(1, Number(numDecIntervals));
framePadding = Math.max(0, Number(framePadding));
borderThickness = Math.max(0, Number(borderThickness));
outerMargin = Math.max(0, Number(outerMargin));
fontSize = Math.max(1, Number(fontSize));
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Calculate canvas dimensions
// Ensure non-negative dimensions even if originalImg is tiny or params are zero
const imgWidth = originalImg.width || 0;
const imgHeight = originalImg.height || 0;
const canvasWidth = imgWidth + 2 * framePadding + 2 * outerMargin;
const canvasHeight = imgHeight + 2 * framePadding + 2 * outerMargin;
// Prevent 0x0 canvas if all inputs lead to it, ensure at least 1x1
canvas.width = Math.max(1, canvasWidth);
canvas.height = Math.max(1, canvasHeight);
// 1. Background Color
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Coordinate definitions
const innerFrameX = outerMargin;
const innerFrameY = outerMargin;
const innerFrameWidth = imgWidth + 2 * framePadding;
const innerFrameHeight = imgHeight + 2 * framePadding;
const imageX = outerMargin + framePadding;
const imageY = outerMargin + framePadding;
// 2. Grid Lines (if showGrid is 1)
if (Number(showGrid) === 1 && innerFrameWidth > 0 && innerFrameHeight > 0) {
ctx.strokeStyle = gridLineColor;
ctx.lineWidth = 1;
// Vertical grid lines
if (numRaIntervals > 1) { // Only draw if there's more than one interval
const raGridStep = innerFrameWidth / numRaIntervals;
for (let i = 1; i < numRaIntervals; i++) {
const x = innerFrameX + i * raGridStep;
ctx.beginPath();
ctx.moveTo(x, innerFrameY);
ctx.lineTo(x, innerFrameY + innerFrameHeight);
ctx.stroke();
}
}
// Horizontal grid lines
if (numDecIntervals > 1) { // Only draw if there's more than one interval
const decGridStep = innerFrameHeight / numDecIntervals;
for (let i = 1; i < numDecIntervals; i++) {
const y = innerFrameY + i * decGridStep;
ctx.beginPath();
ctx.moveTo(innerFrameX, y);
ctx.lineTo(innerFrameX + innerFrameWidth, y);
ctx.stroke();
}
}
}
// 3. Draw original image
if (imgWidth > 0 && imgHeight > 0) {
ctx.drawImage(originalImg, imageX, imageY, imgWidth, imgHeight);
}
// 4. Main Border
if (borderThickness > 0 && innerFrameWidth > 0 && innerFrameHeight > 0) {
ctx.strokeStyle = frameColor;
ctx.lineWidth = borderThickness;
ctx.strokeRect(innerFrameX, innerFrameY, innerFrameWidth, innerFrameHeight);
}
// 5. Ticks and Labels (only if outerMargin allows)
if (outerMargin > fontSize) { // Basic check if there's space for labels
ctx.font = `${fontSize}px monospace`;
ctx.fillStyle = labelColor;
ctx.strokeStyle = frameColor; // Ticks will use frameColor
ctx.lineWidth = 1; // Ticks are thin
const tickLength = Math.max(1, outerMargin * 0.2);
const majorTickLength = Math.max(1, outerMargin * 0.35);
const labelOffset = fontSize * 0.5;
const isMajorTick = (index, totalIntervals) => {
if (index === 0 || index === totalIntervals) return true;
if (totalIntervals % 2 === 0 && index === totalIntervals / 2) return true;
return false;
};
// Top Ticks & Labels (RA-like)
if (innerFrameWidth >= 0) { // Check if frame has non-negative width
const raTickStep = (numRaIntervals > 0 && innerFrameWidth > 0) ? innerFrameWidth / numRaIntervals : 0;
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
for (let i = 0; i <= numRaIntervals; i++) {
const x = innerFrameX + i * raTickStep;
const currentTickLength = isMajorTick(i, numRaIntervals) ? majorTickLength : tickLength;
ctx.beginPath();
ctx.moveTo(x, innerFrameY);
ctx.lineTo(x, innerFrameY - currentTickLength);
ctx.stroke();
const raValue = (numRaIntervals > 0) ? (i * (24 / numRaIntervals)) : 0;
const raLabel = (raValue % 1 === 0) ? raValue.toString() : raValue.toFixed(1);
ctx.fillText(`${raLabel}h`, x, innerFrameY - currentTickLength - labelOffset);
}
}
// Bottom Ticks & Labels (RA-like)
if (innerFrameWidth >= 0) {
const raTickStep = (numRaIntervals > 0 && innerFrameWidth > 0) ? innerFrameWidth / numRaIntervals : 0;
ctx.textBaseline = 'top';
for (let i = 0; i <= numRaIntervals; i++) {
const x = innerFrameX + i * raTickStep;
const currentTickLength = isMajorTick(i, numRaIntervals) ? majorTickLength : tickLength;
ctx.beginPath();
ctx.moveTo(x, innerFrameY + innerFrameHeight);
ctx.lineTo(x, innerFrameY + innerFrameHeight + currentTickLength);
ctx.stroke();
const raValue = (numRaIntervals > 0) ? (i * (24 / numRaIntervals)) : 0;
const raLabel = (raValue % 1 === 0) ? raValue.toString() : raValue.toFixed(1);
ctx.fillText(`${raLabel}h`, x, innerFrameY + innerFrameHeight + currentTickLength + labelOffset);
}
}
// Left Ticks & Labels (DEC-like)
if (innerFrameHeight >= 0) {
const decTickStep = (numDecIntervals > 0 && innerFrameHeight > 0) ? innerFrameHeight / numDecIntervals : 0;
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
for (let i = 0; i <= numDecIntervals; i++) {
const y = innerFrameY + i * decTickStep;
const currentTickLength = isMajorTick(i, numDecIntervals) ? majorTickLength : tickLength;
ctx.beginPath();
ctx.moveTo(innerFrameX, y);
ctx.lineTo(innerFrameX - currentTickLength, y);
ctx.stroke();
let decValue = (numDecIntervals > 0) ? (90 - (i * (180 / numDecIntervals))) : 0;
decValue = Math.round(decValue);
const decLabel = (decValue >= 0 ? '+' : '') + decValue + '°'; // Show + for 0 too for consistency
if (decValue === 0) decLabel = '0°'; // No sign for 0
ctx.fillText(decLabel, innerFrameX - currentTickLength - labelOffset, y);
}
}
// Right Ticks & Labels (DEC-like)
if (innerFrameHeight >= 0) {
const decTickStep = (numDecIntervals > 0 && innerFrameHeight > 0) ? innerFrameHeight / numDecIntervals : 0;
ctx.textAlign = 'left';
// ctx.textBaseline = 'middle'; // already set
for (let i = 0; i <= numDecIntervals; i++) {
const y = innerFrameY + i * decTickStep;
const currentTickLength = isMajorTick(i, numDecIntervals) ? majorTickLength : tickLength;
ctx.beginPath();
ctx.moveTo(innerFrameX + innerFrameWidth, y);
ctx.lineTo(innerFrameX + innerFrameWidth + currentTickLength, y);
ctx.stroke();
let decValue = (numDecIntervals > 0) ? (90 - (i * (180 / numDecIntervals))) : 0;
decValue = Math.round(decValue);
const decLabel = (decValue >= 0 ? '+' : '') + decValue + '°';
if (decValue === 0) decLabel = '0°';
ctx.fillText(decLabel, innerFrameX + innerFrameWidth + currentTickLength + labelOffset, y);
}
}
}
return canvas;
}
Apply Changes