Displaying an element outside with reduced opacity using fabric js and controls placed above overlay

The property controlsAboveOverlay in Fabric.js is a boolean that, when set to true, will display the controls (borders, corners, etc.) of an object above the overlay image. The overlay image is an image that can be placed on top of the canvas.

Currently, it is resulting in the appearance shown below. The outer part displays only the controls.

https://i.sstatic.net/2fsKOXgM.png

I want to achieve a look where the outer part of the element has a 0.5 opacity. Like this:

https://i.sstatic.net/wDofglY8.png

Below is a sample HTML code snippet for reference:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Fabric.js Example with controlsAboveOverlay</title>
    <!-- Importing the Fabric.js library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
  </head>
  <body>
    <!-- Creating a canvas element with id 'canvas' -->
    <canvas id="canvas" width="400" height="400"></canvas>
    <style>
      .canvas-container {
        /* Setting the background color of the canvas container */
        background-color: #f0f0f0;
      }
    </style>
    <script>
      (function () {
        /* Initializing a new Fabric.js canvas with certain properties */
        var canvas = new fabric.Canvas("canvas", {
          width: 600,
          height: 500,
          backgroundColor: "#ffffff",
          /* Setting controlsAboveOverlay to true to render controls above the overlay image */
          controlsAboveOverlay: true,
        });

        /* Creating a rectangular clip path */
        var clipPath = new fabric.Rect({
          width: 300,
          height: 300,
          left: (canvas.getWidth() - 300) / 2,
          top: 10,
        });

        /* Creating a group of objects, in this case, a single rectangle */
        var group = new fabric.Group([
          new fabric.Rect({
            width: 100,
            height: 100,
            fill: "red",
            left: (canvas.getWidth() - 150) / 2,
            top: 10,
          }),
        ]);

        /* Applying the clip path to the canvas */
        canvas.clipPath = clipPath;

        /* Adding the group of objects to the canvas */
        canvas.add(group);
      })();
    </script>
  </body>
</html>

Answer №1

Unique Solution

Create a custom path using SVG clipping technique

    <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Innovative approach with Fabric.js</title>
    <!-- Including Fabric.js library from CDN -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
  </head>
  <body>
    <!-- Creating canvas element with id 'canvas' -->
    <canvas id="canvas" width="400" height="400"></canvas>
    <style>
      .canvas-container {
        /* Styling the canvas container background color */
        background-color: #f0f0f0;
      }
    </style>
    <script>
      (function () {
        /* Initializing Fabric.js canvas with specified properties */
        var canvas = new fabric.Canvas("canvas", {
          width: 600,
          height: 600,
          backgroundColor: "#ffffff",
          /* Configuring preserveObjectStacking to avoid object overlap on overlay */
          preserveObjectStacking: true,
        });

        var top = 150; // y-coordinate of inner clipping rectangle origin
        var left = 150; // x-coordinate of inner clipping rectangle origin

        var canvasPadding = 2000; // padding for canvas area
        var paddingHalf = canvasPadding / 2; // half the padding size
        var viewWidth = 300; // width of inner clipping rectangle
        var viewHeight = 300;   // height of inner clipping rectangle

        /* Defining SVG mask for the canvas */

        var maskPath = `M 0 0 L ${canvasPadding} 0 L ${canvasPadding} ${canvasPadding} L 0 ${canvasPadding} L0 0 Z
          M ${paddingHalf + top} ${paddingHalf + top}
          L ${paddingHalf + left} ${paddingHalf + top + viewHeight}
          L ${paddingHalf + left + viewWidth} ${paddingHalf + top + viewHeight}
          L ${paddingHalf + left + viewWidth} ${paddingHalf + top}
          L ${paddingHalf + left} ${paddingHalf + top} Z
        `;

        var mask = new fabric.Path(maskPath, {
          fill: "rgba(0, 0, 0)",
          opacity: 0.5,
          left: -paddingHalf,
          top: -paddingHalf,
          selectable: false,
          evented: false,
        });

        /* Creating group of objects, here a single rectangle */
        var group = new fabric.Group([
          new fabric.Rect({
            top: 0,
            left: 0,
            width: 100,
            height: 100,
            fill: "red",
            left: (canvas.getWidth() - 150) / 2,
            top: 10,
          }),
        ]);

        /* Adding object group to the canvas */
        canvas.add(group);
        canvas.add(mask);
      })();
    </script>
    </body>
   </html>

Answer №2

We aim to display only the exterior portion of the image with a semi-transparent effect.

To achieve a similar outcome, we utilize two overlapping elements:

Essentially, each object we add will have a copy created with a semi-transparent filter applied, resulting in two instances for every effect. The concept is that when the image shifts beyond the canvas boundary, the original version gets clipped while the duplicate (with semi-transparency) displays externally. For this purpose, we adjust the position of the duplicate image when the original one moves.

Below is a sample HTML code snippet:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Blur/Opacity Effect of Fabric.js Example</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
  </head>
  <body>
    <canvas id="canvas" width="1200" height="500"></canvas>
    <style>
      body {
        margin: 0;
        overflow: hidden;
      }
    </style>
    <script>
      // JavaScript logic to implement the desired effect
    </script>
  </body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Inject an HTML or jade webpage into a div within another HTML or jade webpage

I'm facing an issue in my Node.js project with a script (JS) that is responsible for loading a Jade page into a div of another Jade page using $("#div").load(directory). Despite specifying the directory of the jade page to be loaded, I keep getting an ...

Examining whether an ajax call was not initiated within an Angular application

Is there a way to verify that an ajax request has not been made using Angular's $httpBackend? I attempted to use verifyNoOutstandingRequest() but it doesn't seem to be triggering test failures in version 1.1.5. Here is more information about the ...

Is there a way to log and process div data posted using jQuery in CSS format?

I am looking to extract and log a JavaScript-calculated result from an anonymous survey created using a WordPress plugin. The generated HTML code is: <div ref="fieldname57_1" class="cff-summary-item"> <span class="summary-field-title cff-summary ...

Is there a way to identify the source of a div's scrolling behavior?

While working on a complex web page that involves multiple JQuery Dialogs and other widgets, I encountered a frustrating issue. Some of the dialogs contain divs with scrolling abilities (using overflow-y with a fixed height). Whenever I click on one dialog ...

Setting Start and End Dates in Bootstrap Vue Datepicker to Ensure End Date is After Start Date

My Vue.js form includes two BootstrapVue datepickers for holiday management. Users can define the start date and end date of their holiday, with the condition that the end date must be equal to or greater than the start date. Here is my current implementat ...

initiating a submission upon the occurrence of an onchange event on an input field of type "file"

I have encountered an issue while trying to submit a form using the onchange event of an input element with type file. The problem is that it submits an empty form even when a file has been chosen. Here is the code snippet: var form = document.createElem ...

Arranging numbers in JavaScript lists

empList = [ { "Account": "AAA - 0029", "Available": "$100" }, { "Account": "BBB- 0146", "Available": "200" }, { "Account": "AAA - 1812", "Available": "300"}, { "Account": "CCC- 2019", "Available": "400"}, { "Account" ...

Is there a way to easily duplicate this and add a navigation bar and logo to every page?

Why is it that when I copy and paste this code into any .html document, it only runs correctly on the resources tab? The logo is only showing up on the resources page, even though it's using the same css stylesheet and html structure. <div class=" ...

Flow bar for micro-tasks

In my current project, I am faced with the task of organizing a series of 4 mini tasks and displaying to the end user which specific mini task they are currently on. To accomplish this, I have been utilizing image tags for each task. <img>1</img ...

How to verify changes in session variable using PHP and AJAX

Hey there! I'm looking for a way to continually monitor changes in a session variable within PHP. Let's say the session variable "x" starts off with a value of "1" and then, after five seconds, it changes to "2". This session variable "x" is up ...

``There was an issue with the connection while fetching data using Nextjs middleware

I've encountered an issue where this code works perfectly fine in dev mode but fails when switched to production mode. Can anyone help me figure out what's causing the fetch failure? export default async function middleware(req: NextRequest) { ...

Integrate, Delay, Experimentalize, and Attach components

This inquiry might lean more towards a general browser/javascript discussion rather than a focused prototype question, but I believe this community possesses a deep understanding of javascript and browsers. With that said, here is my query: If the followi ...

Prevent table headers from scrolling in Bootstrap Vue by following these steps

Just starting out with bootstrap vue and I've been using version 1.4 for my application. I've utilized b-table for displaying my data, but I'm encountering a problem where the table headers also scroll along with the content. I'd like t ...

Why isn't the float left property working as expected?

Why won't my image float to the left? I'm using a class called align-left with float: left but it's not working. You can see the live version at - (check out the review grid halfway down under the heading 'High customer satisfaction r ...

Struggling with the alignment of pictures inside a container

I utilized the Instafeed.js library to fetch the three most recent images from an Instagram account. These images are loaded into a specific div and I successfully customized their styling according to my requirements. However, the current setup is quite s ...

Setting environment variables using the node command is successful on Linux and macOS platforms, however, it may not function properly

When I clone a project using git, I encounter issues running npm run build on Windows. The command works fine on Mac and Linux: "build": "API=https://dev-api.myexample.com/v1.0 babel-node build.js", An error message is displayed: 'API' is no ...

Displaying the loading image only on the first result within a while loop

When a submit button is clicked on any result, the loading image below the button displays only for the first result in the while loop. For example, if I click the submit button on the first result, the loading image shows below it. However, when I click t ...

In Vue, you can dynamically load a JavaScript file containing a JavaScript object during runtime

I'm in the process of developing a no-code application with Vue. I have come across an issue where I cannot add functions to a JSON file that I want to import at runtime. As a workaround, I decided to use a JavaScript or TypeScript file to store the J ...

Issues with displaying HTML5 audio player in iOS Chrome and Safari browsers

My html5/jquery/php audio player is working well on desktop browsers, but when I tried testing it on iOS, all I could see was a grey track bar. I suspect that the controls are hidden behind the track bar because sometimes the associated file starts playing ...

"Looking to access your Express app in a VM from the internet? Here's how

I have an express app running on a Node.js server hosted on Azure Linux VM, and I am looking to access this website from my personal computer. const express = require('express'); const app = express(); app.listen(3000, () => { console.lo ...