<svg x="0" y="0" height="2048" width="4096" style="position: absolute; top: 0px; left: 0px; pointer-events: none;">
<defs>
<mask x="0" y="0" id="shadowLayerMask">
<polygon fill="#FFF" points="1042,1578 630,2048 3902,2048 3370,1464"></polygon>
</mask>
</defs>
<rect x="0" y="0" fill="red" mask="url(#shadowLayerMask)" maskContentUnits="userSpaceOnUse" height="2048" width="4096"></rect>
</svg>
Simple right? Here's the thing, if I drop this svg into an html file, the masking works perfectly. But when I generate the same svg with virtual dom, the mask has no effect and we just have a huge red rect.
Annoyingly I can get it to display when generated, if I open the developer tools and add a pointless <defs></defs>
to the svg. That seems to kick the svg somehow and remind it that it needs to mask.
Anyone know what is going on here? Is there a workaround that doesn't involve setting a timer to inject an empty defs
?
here is the source
render : Layer -> Html
render { key, shader, mask, size } =
let
key' =
key ++ "LayerMask"
style' =
[ "position" => "absolute"
, "top" => "0px"
, "left" => "0px"
, "pointer-events" => "none"
]
hw =
[ A.height << toString <| getY size
, A.width << toString <| getX size
]
polygon =
Svg.polygon
[ A.fill "#FFF"
, toPoints mask
]
[]
mask' =
node
"mask"
[ A.x "0", A.y "0", id key' ]
[ polygon ]
image =
Svg.rect
(A.x "0"
::
A.y "0"
-- :: A.xlinkHref shader
::
A.fill "red"
::
A.mask (url key')
::
A.maskContentUnits "userSpaceOnUse"
::
hw
)
[]
in
Svg.svg
(A.x "0" :: A.y "0" :: style style' :: hw)
[ Svg.defs [] [ mask' ]
, image
]
here are some relevant imports
import Html exposing (..)
import Svg
import Svg.Attributes as A
import Html.Attributes as H exposing (style, id)
Figured it out with help from comments. It was node
vs Svg.node
. When I changed it to Svg.node
the problem went away. Question is:
Its cause of this 2 lines:
import Html exposing (..)
import Svg
The first one imports all attributes of Html
including node
the second just import the Svg
namespace. So when you are using node
in this the environment node
is the Html.node
. You would get an compile error with this imports:
import Html exposing (..)
import Svg exposing (..)
or this:
import Html exposing (node)
import Svg exposing (node)
cause then, Elm did not know which node
you want to use.
So its safer to import the functions that you needed and not using (..)
So the main question is why does Html.node
accepts List Svg.Attribute
without throwing an error. Its cause Svg.Attribute
and Html.Attribute
are not real types but type aliases for VirtualDom.Property
. So for the compiler both are the same type. Same for Htm.Html
and Svg.Svg
which are both aliases for VirtualDom.Node
.
In the end both node
functions have the Signature
String -> List VirtualDom.Property -> List VirtualDom.Node -> VirtualDom.Node
so the compiler cant distinguish between them.
Just for reference, here is the code for both node
functions:
--Html.node
node : String -> List Attribute -> List Html -> Html
node =
VirtualDom.node
--Svg.node
node : String -> List Attribute -> List Svg -> Svg
node name =
\attributes children ->
VirtualDom.node name (svgNamespace :: attributes) children
Maybe the compiler should warn you when this happens.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With