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.

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

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

Divide the promised variable into separate named variables

Here is a code snippet that I am working with: Promise.all( categories.map(category => Collection.find({ category })) ).then(items => { return items }) Currently, the output is an array with the same length as categories, where each element is ...

The website's content is displayed as a mobile-friendly menu

I've been working on creating a responsive menu using HTML and CSS, and everything is functioning well so far. However, I'm facing an issue with the mobile view of the menu. When the menu opens up, it obstructs the text below it, making it diffic ...

After refreshing the page, the ngRoute white page is displayed

I've encountered an issue with my Angular website. I built it using ngRoute, but when I click on a link, a white page appears. Only after refreshing the page does the content actually show up. Even in the browser's DevTools, you can see the html ...

Vue snapshot testing is encountering a failure with the error message "TypeError: Cannot read property of undefined"

Everything seems to be working fine with the component on the page without any errors. Storybook is also functioning well, but the problem lies in the unit test. import { mount } from '../../vue'; import { createLocalVue } from '@vue/test-u ...

The HTML link is not directly attached to the text, specifically in Internet Explorer

When viewing my website in Chrome, the menu links in the Header function correctly. However, in Internet Explorer (specifically version 11), hovering over 'HOME,' 'LISTINGS,' or 'AGENTS' reveals that the displayed URL is incor ...

I'm having trouble accessing my POST data using console.log. Instead of getting the expected data, all I see in the console when I try to GET is "

My code for the POST function is working, but when I try to retrieve and display the POST response from the server, all I get is "null". Can anyone help me figure out how to properly send data from my form to the server and then successfully console log it ...

The file always fails the Regex test in Node.js

I am dealing with a log file that contains lines structured like this: [Thu Mar 30 2017 11:24:51 GMT+0100 (WEST)] {"serial":"CA-2M-1107619","type":"iface","body":{"action":"up","device":"tun_man","ip":"127.255.0.10","ip6":"2016:900d:c0de::1001"} My goal ...

Interacting with a Hapi JS API through a distinct Vue JS Frontend. The data in request.payload is not defined

As I take my first steps on Hapi JS, I am facing the challenge of connecting my app to a SQL Server DB. My current task involves sending login data from a Vue CLI JS frontend to a Hapi JS Api using axios. The login process essentially consists of a "SELEC ...

Difficulties encountered when adjusting the size or reducing the images in a Cycle2 slideshow

Greetings to all fellow coders! Thank you for taking the time to read this post. I am currently facing a challenge in my web development project where I am trying to make my Cycle 2 slideshow images resize and reposition alongside other divs when the wind ...

Displaying modal popups limited to one per session

Is there a way to display this Dialog Popup only once per session? I have looked into using cookies for configuration, but haven't been able to implement it in this scenario: $(document).ready(function() { ShowDialog(true); e. ...

adjusting array based on screen size fluctuations

Imagine having two arrays of images named landscape_images[] and portrait_images[]. One is for the landscape view and the other for the portrait view. When the screen width is in landscape mode, the wide resolution images will be displayed on the body. C ...

Issue arises when component is mistakenly displayed in the header upon deployment on Vercel platform

When deploying my NextJS app to Vercel, I encounter an issue where state-based modals that should be hidden are displaying. Additionally, the modals are rendering in the header instead of center-screen as expected. Surprisingly, these problems do not occur ...

performing functions concurrently within angularjs

I am currently utilizing angularjs 1.0 within my application. There is a dropdown on my cshtml page <select tabindex="2" id="Employee" ng-model="models.SelectedEmployee" ng-change="changeEmployee()" disabled="disabled" class="Answer" size="6"> < ...

Using AngularJs to have two ui-views on a single page

As a beginner in AngularJs, I encountered an issue with having two ui-views on the same page. When I click a button to show the view for goals, both the form for goals appear in ui-view 1 and ui-view 2 simultaneously. I have been working with states but I ...

Personalizing the look of Stripe Payment Component in a React Application

Currently, I have integrated the Stripe Payment Element into my React application using the code snippet below: import { useStripe, useElements, PaymentElement, } from '@stripe/react-stripe-js' export const PaymentDetails = () => { const st ...

JavaScript event manually triggered not propagating within an element contained in an iFrame context

I am currently developing a WYSIWYG designer that enables users to choose colors through [input type="color"] fields. The interface includes inputs on the left side and an iFrame on the right side displaying the generated preview. Normally, when ...

Having trouble seeing the output on the webpage after entering the information

I can't seem to figure out why the result is not displaying on the HTML page, so for now I have it set up as an alert. <h1>Factorial Problem</h1> <form name="frm1"> Enter any number :<input type="text" name="fact1"& ...

Take a custom action once all elements have been rendered with ng-repeat

Looking to manipulate a DIV element generated by ng-repeat: <div ng-repeat="data in info" > <div id='plot_{{data.id}}'></div> </div> Here is the sequence of events: Information added to $scope.info ng-repeat exec ...

Incorporating CASL with the latest version of Angular, version

I'm currently working on implementing CASL into my Angular application, but I'm having trouble understanding how to integrate it. // Login Component ngOnInit() { var jsonBody = {}; jsonBody['email'] = 'peter@klaven'; ...

"Revamping the text style of input materials in React JS: A step-by

How can I modify the style of the text field component in Material UI? Specifically, I would like to change the appearance of the text that the user enters. I have attempted to use the Material API, but it has not provided the desired results. Here is an ...