Search code examples
paperjs

paper.js: Any way to use onMouseEnter/Leave with transparent path fill?


I have a paper.js vector scene containing paths with an outline but no- or a transparent fill. The onMouseEnter/onMouseLeave events attached to each path fire correctly when the paths have a fill colour with any non-zero alpha value, e.g. #00000001. When the fill is transparent or absent I only trigger the onMouseEnter events when the cursor happens to touch the outline as I move it over the shape.

While the minimal alpha solution works, or I could ensure that the fill colour matches the background colour, I have overlapping shapes and would prefer a solution that doesn't require nearly-correct hacks like that that might cause issues as many shapes stack up.

This example uses global hit-testing and I think I can make it work with some re-architecting. Is this the best approach?

Is there any way to have a transparently filled path fire onMouseEnter events consistently as the cursor moves inside the shape?


Solution

  • paper.js works quite hard to exclude transparent paths from hit results. In the end the most pragmatic thing that worked for me was to patch the individual Paths I'm interested in. I'm using Typescript, hence the annotations:

    (myPath as any)._hitTestSelf = function(point: paper.Point): paper.HitResult | undefined {
        // This conditional replaces the original paper.Item one:
        // if (options.fill && this.hasFill() && this._contains(point))
        if (this._contains(point)) 
            // HitResult doesn't expose a constructor; we need to build it ourselves.
            const result = new paper.HitResult()
            result.type = 'fill'
            result.item = this
            return result
        }
    }
    

    I know there are a bunch of caveats around efficiency, monkey patching in general etc. that I'm probably ignoring but, well, WFM.

    BTW, I'd love to see allowTransparent as an option for hit testing in paper.js. Having dug through the source I don't think this would be too hard?