fabricjs / fabric.js

Javascript Canvas Library, SVG-to-Canvas (& canvas-to-SVG) Parser
http://fabricjs.com
Other
29.17k stars 3.52k forks source link

[Feature]: Shadow Rendering Issue in Fabric.js 6.3.0 for Transparent Circle, Rect #10142

Open yashChapaniOB opened 2 months ago

yashChapaniOB commented 2 months ago

CheckList

Description

In Fabric.js version 6.3.0, when applying a shadow to a transparent circle,Rect the shadow appears inside the circle,rect as well, instead of being limited to the outer area of the circle,Rect. The desired behavior is for the shadow to be rendered outside the circle's or Rect's boundary, without affecting the inner transparent area.

Current Behavior

Currently, when a shadow is applied to a Rect or Circle, the shadow is visible within the object's boundary, which includes the transparent areas. This behavior deviates from the expected result, where the shadow should be projected outside the shape's edge, leaving the inner transparent regions unaffected.

Current State

var option = {}; option['objectCaching'] = true; option['isLocked'] = false; option['element_type'] = "basicShape";

let ctx = this.canvas.getContext('2d');

const shadow = new Shadow({ affectStroke: false blur:0 color:"#000000ff", includeDefaultValues:true, nonScaling:false, offsetX:50, offsetY:50, });

var rect = new Rect({ angle: 0, fill: #FFDE59 borderColor: '#0069FF', borderScaleFactor: 1.5, centeredScaling: false, centeredRotation: true, cornerSize: 15, cornerColor: '#0069FF', cornerStyle: 'circle', shadow: shadow, lockScalingFlip: true, isLocked: false, visible: true, stroke: "#ffffffff" selectionDashArray: [], clipPath: undefined, excludeFromExport: false, strokeWidth: 0, transparentCorners: false, rx: 0, ry:0, _controlsVisibility: { tl: true, tr: true, br: true, bl: true, ml: true, mt: true, mr: true, mb: true, mtr: true }, type: 'rect', element_type: 'basicShape', ...option });

this.canvas.add(rect); this.canvas.renderAll();

image

Expected Behavior

The shadow should be rendered outside the Rect or Circle boundaries, not within the shape's transparent inner area.

Additional Context

No response

asturur commented 2 months ago

that is not how shadow for the canvas works sadly and there isn't a performing fix that makes sense. You would have to draw the shapes twice, one normally and one with global composite operation set to copy.

That would also delete anything that is under the shape with the shape itself.

Clemweb commented 1 month ago

@yashChapaniOB can you tell me how you do in v6 the rounded rectangle for middles handlers ?

asturur commented 1 month ago

You have to write your own control render function. Please look at the standard control.render function and write your own with a rounded rect.

Clemweb commented 1 month ago

@asturur don't find control.render, can you give a sample or the file for search in ? Thanks

asturur commented 1 month ago

https://github.com/fabricjs/fabric.js/blob/master/src/controls/Control.ts#L348

Clemweb commented 1 month ago

@asturur ok I write this :

`Control.prototype.render = function(ctx, left, top, styleOverride, fabricObject) { const size = 10; // Taille du handler const radius = 5; // Rayon des coins du rectangle ctx.save(); ctx.translate(left, top); ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor;

    ctx.beginPath();
    ctx.moveTo(-size + radius, -size);
    ctx.lineTo(size - radius, -size);
    ctx.quadraticCurveTo(size, -size, size, -size + radius);
    ctx.lineTo(size, size - radius);
    ctx.quadraticCurveTo(size, size, size - radius, size);
    ctx.lineTo(-size + radius, size);
    ctx.quadraticCurveTo(-size, size, -size, size - radius);
    ctx.lineTo(-size, -size + radius);
    ctx.quadraticCurveTo(-size, -size, -size + radius, -size);
    ctx.closePath();

    ctx.fill();

    // Dessiner la bordure
    ctx.lineWidth = 1; // Épaisseur de la bordure
    ctx.strokeStyle = '#000000'; // Couleur de la bordure
    ctx.stroke();

    ctx.restore();
};`

It's working, but how to know if it draw the top left corner ? or middle right ?

asturur commented 1 month ago

Please read this carefully https://fabricjs.github.io/docs/configuring-controls/ and decide which approach is best for you to configure your controls first.

Then create a render function for each type of rendering you need, then assign it to the correct control. You can create a new control class and instantiate it in the createControls function for your object type or assign it to the existing control instances every time the objects are created.