Please bookmark this page to avoid losing your image tool!

Image Field Of View Visualizer

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(
    originalImg, 
    type = 'cone', 
    observerX = 50, 
    observerY = 50, 
    radius = 50, 
    fovAngle = 90, 
    direction = 0, 
    darkness = 0.8,
    showGuidelines = 'true',
    guidelineColor = '#00ffcc'
) {
    // Canvas setup
    const canvas = document.createElement('canvas');
    const w = originalImg.width;
    const h = originalImg.height;
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext('2d');

    // Draw the original image onto the main canvas
    ctx.drawImage(originalImg, 0, 0);

    // Create an overlay canvas for the darkness/lighting effect
    const overlay = document.createElement('canvas');
    overlay.width = w;
    overlay.height = h;
    const oCtx = overlay.getContext('2d');

    // Fill the overlay with darkness
    oCtx.fillStyle = `rgba(0, 0, 0, ${Number(darkness)})`;
    oCtx.fillRect(0, 0, w, h);

    // Set composite operation to 'erase' the FOV area from the darkness
    oCtx.globalCompositeOperation = 'destination-out';

    // Parse and calculate variables
    const obsX = w * (Number(observerX) / 100);
    const obsY = h * (Number(observerY) / 100);
    const diag = Math.sqrt(w * w + h * h);
    // Ensure radius is at least 1 to avoid gradient errors
    const absRadius = Math.max(1, diag * (Number(radius) / 100)); 
    
    // Direction 0 is UP (North). Subtracting 90 degrees to align with standard canvas rotation where 0 is East.
    const dirRad = (Number(direction) - 90) * Math.PI / 180;
    const fovRad = Number(fovAngle) * Math.PI / 180;
    
    const startAngle = dirRad - (fovRad / 2);
    const endAngle = dirRad + (fovRad / 2);
    
    const t = String(type).toLowerCase();

    // Draw the FOV map on the overlay (this punches a hole through the darkness)
    if (t === 'cone') {
        oCtx.beginPath();
        oCtx.moveTo(obsX, obsY);
        oCtx.arc(obsX, obsY, absRadius, startAngle, endAngle);
        oCtx.closePath();

        const gradient = oCtx.createRadialGradient(obsX, obsY, 0, obsX, obsY, absRadius);
        gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
        gradient.addColorStop(0.7, 'rgba(255, 255, 255, 1)');
        gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
        
        oCtx.fillStyle = gradient;
        oCtx.fill();
    } else if (t === 'circle') {
        const gradient = oCtx.createRadialGradient(obsX, obsY, 0, obsX, obsY, absRadius);
        gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
        gradient.addColorStop(0.6, 'rgba(255, 255, 255, 1)');
        gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
        
        oCtx.beginPath();
        oCtx.arc(obsX, obsY, absRadius, 0, 2 * Math.PI);
        oCtx.fillStyle = gradient;
        oCtx.fill();
    } else if (t === 'binocular') {
        const offset = absRadius * 0.35;
        const bRadius = Math.max(1, absRadius * 0.6);

        const drawBino = (cx, cy) => {
            const gradient = oCtx.createRadialGradient(cx, cy, 0, cx, cy, bRadius);
            gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
            gradient.addColorStop(0.7, 'rgba(255, 255, 255, 1)');
            gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
            
            oCtx.beginPath();
            oCtx.arc(cx, cy, bRadius, 0, 2 * Math.PI);
            oCtx.fillStyle = gradient;
            oCtx.fill();
        };

        drawBino(obsX - offset, obsY);
        drawBino(obsX + offset, obsY);
    }

    // Blend the darkness mask over the original image
    ctx.drawImage(overlay, 0, 0);

    // Draw technical visualization guidelines if enabled
    if (String(showGuidelines).toLowerCase() === 'true') {
        ctx.strokeStyle = String(guidelineColor);
        ctx.fillStyle = String(guidelineColor);
        ctx.lineWidth = 2;

        // Draw observer point
        ctx.beginPath();
        ctx.arc(obsX, obsY, Math.max(3, w * 0.005), 0, 2 * Math.PI);
        ctx.fill();

        // Draw bounds
        ctx.setLineDash([5, 5]);
        
        if (t === 'cone') {
            ctx.beginPath();
            ctx.moveTo(obsX, obsY);
            ctx.arc(obsX, obsY, absRadius, startAngle, endAngle);
            ctx.closePath();
            ctx.stroke();
        } else if (t === 'circle') {
            ctx.beginPath();
            ctx.arc(obsX, obsY, absRadius, 0, 2 * Math.PI);
            ctx.stroke();
        } else if (t === 'binocular') {
            const offset = absRadius * 0.35;
            const bRadius = absRadius * 0.6;
            
            ctx.beginPath();
            ctx.arc(obsX - offset, obsY, bRadius, 0, 2 * Math.PI);
            ctx.stroke();
            
            ctx.beginPath();
            ctx.arc(obsX + offset, obsY, bRadius, 0, 2 * Math.PI);
            ctx.stroke();
        }
        ctx.setLineDash([]);
    }

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Field of View Visualizer is a tool designed to simulate and visualize visibility ranges within an image. By applying a darkness overlay, it allows users to define specific viewing areas using different shapes such as cones, circles, or binocular-style views. Users can adjust parameters like the observer’s position, the radius of vision, the viewing angle, and the direction of sight. This tool is useful for game developers designing line-of-sight mechanics, security professionals simulating surveillance camera coverage, or photographers planning lighting and compositional visibility.

Leave a Reply

Your email address will not be published. Required fields are marked *