# Showing a circular crop overlay

We can use the [willRenderCanvas](../../api/ui/properties/#willrendercanvas) property to adjust the preview output of the editor.

To apply a circular mask to the output image see the [circular mask example](../mask-image/).

* [ ![](/pintura/static/assets/technologies-mono/javascript.svg)JavaScript](#javascript-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/react.svg)React](#react-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/vue.svg)Vue](#vue-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/svelte.svg)Svelte](#svelte-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/angular.svg)Angular](#angular-panel-0)
* [ ![](/pintura/static/assets/technologies-mono/jquery.svg)jQuery](#jquery-panel-0)

* [index.html](#index-html-panel-0)

```html
<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="./pintura.css" />
</head>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script type="module">
    import { appendDefaultEditor } from './pintura.js';

    const editor = appendDefaultEditor('#editor', {
        src: 'image.jpeg',

        // We'll request a square crop
        imageCropAspectRatio: 1,

        // Let's draw a circle on top of the editor preview when in the crop util
        willRenderCanvas: (shapes, state) => {
            const {
                utilVisibility,
                selectionRect,
                lineColor,
                backgroundColor,
            } = state;

            // Exit if crop utils is not visible
            if (utilVisibility.crop <= 0) return shapes;

            // Get variable shortcuts to the crop selection rect
            const { x, y, width, height } = selectionRect;

            return {
                // Copy all props from current shapes
                ...shapes,

                // Now we add an inverted ellipse shape to the interface shapes array
                interfaceShapes: [
                    {
                        x: x + width * 0.5,
                        y: y + height * 0.5,
                        rx: width * 0.5,
                        ry: height * 0.5,
                        opacity: utilVisibility.crop,
                        inverted: true,
                        backgroundColor: [...backgroundColor, 0.5],
                        strokeWidth: 1,
                        strokeColor: [...lineColor],
                    },
                    // Spread all existing interface shapes onto the array
                    ...shapes.interfaceShapes,
                ],
            };
        },
    });
</script>

```

* [App.jsx](#App-jsx-panel-0)
* [App.css](#App-css-panel-0)

```jsx
import '@pqina/pintura/pintura.css';
import './App.css';
import { PinturaEditor } from '@pqina/react-pintura';
import { getEditorDefaults } from '@pqina/pintura';

const editorDefaults = getEditorDefaults();

function App() {
    return (
        <div className="App">
            <PinturaEditor
                {...editorDefaults}
                src={'image.jpeg'}
                // We'll request a square crop
                imageCropAspectRatio={1}
                // Let's draw a circle on top of the editor preview when in the crop util
                willRenderCanvas={(shapes, state) => {
                    const {
                        utilVisibility,
                        selectionRect,
                        lineColor,
                        backgroundColor,
                    } = state;

                    // Exit if crop utils is not visible
                    if (utilVisibility.crop <= 0) return shapes;

                    // Get variable shortcuts to the crop selection rect
                    const { x, y, width, height } = selectionRect;

                    return {
                        // Copy all props from current shapes
                        ...shapes,

                        // Now we add an inverted ellipse shape to the interface shapes array
                        interfaceShapes: [
                            {
                                x: x + width * 0.5,
                                y: y + height * 0.5,
                                rx: width * 0.5,
                                ry: height * 0.5,
                                opacity: utilVisibility.crop,
                                inverted: true,
                                backgroundColor: [...backgroundColor, 0.5],
                                strokeWidth: 1,
                                strokeColor: [...lineColor],
                            },
                            // Spread all existing interface shapes onto the array
                            ...shapes.interfaceShapes,
                        ],
                    };
                }}
            />
        </div>
    );
}

export default App;

```

```css
.pintura-editor {
    height: 600px;
}

```

* [App.vue](#App-vue-panel-0)

```html
<template>
    <div>
        <PinturaEditor
            v-bind="editorDefaults"
            src="image.jpeg"
            :imageCropAspectRatio="1"
            :willRenderCanvas="willRenderCanvas"
        />
    </div>
</template>
<script>
import { PinturaEditor } from '@pqina/vue-pintura';
import { getEditorDefaults } from '@pqina/pintura';

export default {
    name: 'App',

    components: {
        PinturaEditor,
    },

    data() {
        return {
            editorDefaults: getEditorDefaults(),

            // Let's draw a circle on top of the editor preview when in the crop util
            willRenderCanvas: (shapes, state) => {
                const {
                    utilVisibility,
                    selectionRect,
                    lineColor,
                    backgroundColor,
                } = state;

                // Exit if crop utils is not visible
                if (utilVisibility.crop <= 0) return shapes;

                // Get variable shortcuts to the crop selection rect
                const { x, y, width, height } = selectionRect;

                return {
                    // Copy all props from current shapes
                    ...shapes,

                    // Now we add an inverted ellipse shape to the interface shapes array
                    interfaceShapes: [
                        {
                            x: x + width * 0.5,
                            y: y + height * 0.5,
                            rx: width * 0.5,
                            ry: height * 0.5,
                            opacity: utilVisibility.crop,
                            inverted: true,
                            backgroundColor: [...backgroundColor, 0.5],
                            strokeWidth: 1,
                            strokeColor: [...lineColor],
                        },
                        // Spread all existing interface shapes onto the array
                        ...shapes.interfaceShapes,
                    ],
                };
            },
        };
    },

    methods: {},
};
</script>
<style>
@import '@pqina/pintura/pintura.css';

.pintura-editor {
    height: 600px;
}
</style>

```

* [App.svelte](#App-svelte-panel-0)

```svelte
<script>
    import { PinturaEditor } from '@pqina/svelte-pintura';
    import { getEditorDefaults } from '@pqina/pintura';
    import '@pqina/pintura/pintura.css';

    let editorDefaults = getEditorDefaults();
</script>

<div>
    <PinturaEditor
        {...editorDefaults}
        src={'image.jpeg'}
        imageCropAspectRatio={/* We'll request a square crop */
        1}
        willRenderCanvas={/* Let's draw a circle on top of the editor preview when in the crop util */

        (shapes, state) => {
            const {
                utilVisibility,
                selectionRect,
                lineColor,
                backgroundColor,
            } = state;

            // Exit if crop utils is not visible
            if (utilVisibility.crop <= 0) return shapes;

            // Get variable shortcuts to the crop selection rect
            const { x, y, width, height } = selectionRect;

            return {
                // Copy all props from current shapes
                ...shapes,

                // Now we add an inverted ellipse shape to the interface shapes array
                interfaceShapes: [
                    {
                        x: x + width * 0.5,
                        y: y + height * 0.5,
                        rx: width * 0.5,
                        ry: height * 0.5,
                        opacity: utilVisibility.crop,
                        inverted: true,
                        backgroundColor: [...backgroundColor, 0.5],
                        strokeWidth: 1,
                        strokeColor: [...lineColor],
                    },
                    // Spread all existing interface shapes onto the array
                    ...shapes.interfaceShapes,
                ],
            };
        }}
    />
</div>

<style>
    div :global(.pintura-editor) {
        height: 600px;
    }
</style>

```

* [app.component.ts](#app-component-ts-panel-0)
* [app.component.html](#app-component-html-panel-0)
* [app.component.css](#app-component-css-panel-0)
* [app.module.ts](#app-module-ts-panel-0)

```javascript
import { Component } from '@angular/core';

import { getEditorDefaults } from '@pqina/pintura';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
})
export class AppComponent {
    editorDefaults: any = getEditorDefaults();

    // Let's draw a circle on top of the editor preview when in the crop util
    willRenderCanvas: any = (shapes, state) => {
        const { utilVisibility, selectionRect, lineColor, backgroundColor } =
            state;

        // Exit if crop utils is not visible
        if (utilVisibility.crop <= 0) return shapes;

        // Get variable shortcuts to the crop selection rect
        const { x, y, width, height } = selectionRect;

        return {
            // Copy all props from current shapes
            ...shapes,

            // Now we add an inverted ellipse shape to the interface shapes array
            interfaceShapes: [
                {
                    x: x + width * 0.5,
                    y: y + height * 0.5,
                    rx: width * 0.5,
                    ry: height * 0.5,
                    opacity: utilVisibility.crop,
                    inverted: true,
                    backgroundColor: [...backgroundColor, 0.5],
                    strokeWidth: 1,
                    strokeColor: [...lineColor],
                },
                // Spread all existing interface shapes onto the array
                ...shapes.interfaceShapes,
            ],
        };
    };
}

```

```html
<pintura-editor
    [options]="editorDefaults"
    src="image.jpeg"
    [imageCropAspectRatio]="1"
    [willRenderCanvas]="willRenderCanvas"
></pintura-editor>

```

```css
::ng-deep .pintura-editor {
    height: 600px;
}

```

```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularPinturaModule } from '@pqina/angular-pintura';

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule, AngularPinturaModule],
    exports: [AppComponent],
    providers: [],
    bootstrap: [AppComponent],
})
export class AppModule {}

```

* [index.html](#index-html-panel-0)

```html
<!DOCTYPE html>
<head>
    <link rel="stylesheet" href="./pintura/pintura.css" />
</head>

<script src="./jquery.js"></script>
<script src="./jquery-pintura/useEditorWithJQuery-iife.js"></script>
<script src="./pintura/pintura-iife.js"></script>

<style>
    .pintura-editor {
        height: 600px;
    }
</style>

<div id="editor"></div>

<script>
    useEditorWithJQuery(jQuery, pintura);

    $(function () {
        var editor = $('#editor').pinturaDefault({
            src: 'image.jpeg',

            // We'll request a square crop
            imageCropAspectRatio: 1,

            // Let's draw a circle on top of the editor preview when in the crop util
            willRenderCanvas: (shapes, state) => {
                const {
                    utilVisibility,
                    selectionRect,
                    lineColor,
                    backgroundColor,
                } = state;

                // Exit if crop utils is not visible
                if (utilVisibility.crop <= 0) return shapes;

                // Get variable shortcuts to the crop selection rect
                const { x, y, width, height } = selectionRect;

                return {
                    // Copy all props from current shapes
                    ...shapes,

                    // Now we add an inverted ellipse shape to the interface shapes array
                    interfaceShapes: [
                        {
                            x: x + width * 0.5,
                            y: y + height * 0.5,
                            rx: width * 0.5,
                            ry: height * 0.5,
                            opacity: utilVisibility.crop,
                            inverted: true,
                            backgroundColor: [...backgroundColor, 0.5],
                            strokeWidth: 1,
                            strokeColor: [...lineColor],
                        },
                        // Spread all existing interface shapes onto the array
                        ...shapes.interfaceShapes,
                    ],
                };
            },
        });
    });
</script>

```