You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg,
borderColor = "#B0B0B0", // Color of the main dial border body
borderWidth = 20, // Width of the dial border in pixels (e.g., 20)
markingsColor = "#000000", // Color of the tick marks
showMarkings = 1, // 0 to hide, 1 to show tick marks
numTicks = 60, // Total number of tick positions (e.g., 60)
majorTickInterval = 5, // Every Nth tick is a major tick (e.g., 5). Set to 0 to disable distinct major ticks.
majorTickLengthRatio = 0.7, // Length of major ticks as a ratio of borderWidth (e.g., 0.7)
majorTickWidth = 2, // Width of major ticks in pixels (e.g., 2)
minorTickLengthRatio = 0.4, // Length of minor ticks as a ratio of borderWidth (e.g., 0.4)
minorTickWidth = 1, // Width of minor ticks in pixels (e.g., 1)
showCenterKnob = 1, // 0 to hide, 1 to show center knob
centerKnobColor = "#707070", // Color of the center knob
centerKnobRadiusRatio = 0.1 // Radius of center knob as a ratio of imageRadius (e.g., 0.1 for 10% of image radius)
) {
const imageDiameter = Math.max(0, Math.min(originalImg.width, originalImg.height));
const imageRadius = imageDiameter / 2;
// Sanitize numeric parameters
const BORDER_WIDTH = Math.max(0, Number(borderWidth));
const SHOW_MARKINGS = Number(showMarkings) === 1; // Convert to boolean for easier use
const NUM_TICKS = Math.max(0, Number(numTicks));
const MAJOR_TICK_INTERVAL = Math.max(0, Number(majorTickInterval));
const MAJOR_TICK_LENGTH_RATIO = Math.max(0, Math.min(1, Number(majorTickLengthRatio)));
const MAJOR_TICK_WIDTH = Math.max(0, Number(majorTickWidth));
const MINOR_TICK_LENGTH_RATIO = Math.max(0, Math.min(1, Number(minorTickLengthRatio)));
const MINOR_TICK_WIDTH = Math.max(0, Number(minorTickWidth));
const SHOW_CENTER_KNOB = Number(showCenterKnob) === 1; // Convert to boolean
const CENTER_KNOB_RADIUS_RATIO = Math.max(0, Number(centerKnobRadiusRatio));
const canvasSize = imageDiameter + 2 * BORDER_WIDTH;
const canvas = document.createElement('canvas');
// Handle 0-size canvas case early
if (canvasSize === 0) {
canvas.width = 0;
canvas.height = 0;
return canvas;
}
canvas.width = canvasSize;
canvas.height = canvasSize;
const ctx = canvas.getContext('2d');
const cx = canvas.width / 2;
const cy = canvas.height / 2;
// 1. Draw the dial border background
if (BORDER_WIDTH > 0) {
ctx.fillStyle = borderColor;
ctx.beginPath();
ctx.arc(cx, cy, imageRadius + BORDER_WIDTH, 0, Math.PI * 2);
ctx.fill();
}
// 2. Clip and draw the image
if (imageRadius > 0) {
ctx.save();
ctx.beginPath();
ctx.arc(cx, cy, imageRadius, 0, Math.PI * 2); // Clip to the image area
ctx.clip();
// Determine source crop sx, sy, sDim from originalImg to make it square and centered
const sDim = Math.min(originalImg.width, originalImg.height); // This is imageDiameter
const sx = (originalImg.width - sDim) / 2;
const sy = (originalImg.height - sDim) / 2;
ctx.drawImage(originalImg, sx, sy, sDim, sDim, cx - imageRadius, cy - imageRadius, imageDiameter, imageDiameter);
ctx.restore(); // Remove clipping path for subsequent drawings
}
// 3. Draw tick marks
if (SHOW_MARKINGS && BORDER_WIDTH > 0 && NUM_TICKS > 0) {
ctx.strokeStyle = markingsColor;
const actualMajorTickLength = BORDER_WIDTH * MAJOR_TICK_LENGTH_RATIO;
const actualMinorTickLength = BORDER_WIDTH * MINOR_TICK_LENGTH_RATIO;
for (let i = 0; i < NUM_TICKS; i++) {
const angle = (i / NUM_TICKS) * 2 * Math.PI - Math.PI / 2; // Start from top (North)
const isMajorTick = MAJOR_TICK_INTERVAL > 0 && (i % MAJOR_TICK_INTERVAL === 0);
let currentTickLength;
let currentTickWidth;
if (isMajorTick) {
currentTickLength = actualMajorTickLength;
currentTickWidth = MAJOR_TICK_WIDTH;
} else {
currentTickLength = actualMinorTickLength;
currentTickWidth = MINOR_TICK_WIDTH;
}
// Skip drawing if tick has no effective length or width
if (currentTickLength <= 0 || currentTickWidth <= 0) {
continue;
}
const tickStartX = cx + Math.cos(angle) * imageRadius;
const tickStartY = cy + Math.sin(angle) * imageRadius;
const tickEndX = cx + Math.cos(angle) * (imageRadius + currentTickLength);
const tickEndY = cy + Math.sin(angle) * (imageRadius + currentTickLength);
ctx.lineWidth = currentTickWidth;
ctx.beginPath();
ctx.moveTo(tickStartX, tickStartY);
ctx.lineTo(tickEndX, tickEndY);
ctx.stroke();
}
}
// 4. Draw center knob
if (SHOW_CENTER_KNOB && imageRadius > 0) {
const actualCenterKnobRadius = imageRadius * CENTER_KNOB_RADIUS_RATIO;
if (actualCenterKnobRadius > 0) { // Only draw if knob has positive radius
ctx.fillStyle = centerKnobColor;
ctx.beginPath();
ctx.arc(cx, cy, actualCenterKnobRadius, 0, Math.PI * 2);
ctx.fill();
}
}
return canvas;
}
Apply Changes