Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using xlink:href in SVG can cause pointless style recalculations #62

Open
tomvandezande opened this issue Nov 25, 2016 · 3 comments
Open

Comments

@tomvandezande
Copy link

tomvandezande commented Nov 25, 2016

Edited by @evancz

The runtime behavior of justCirc and symAndUse is very different in the following code.

  • With symAndUse the browser is recalculating styles on every animation frame.
  • With justCirc it does not do this.

You can observe this by profiling the example with the Chrome timeline

import Html exposing (Html)
import Svg exposing (..)
import Svg.Attributes exposing (..)
import VirtualDom exposing (attributeNS)
import AnimationFrame
import Time exposing (Time)


-- PROBLEM

view : Model -> Html Msg
view model =
    let
        justCirc = [ circle [cx "50", cy "50", r "40", strokeWidth "8", stroke "red", fill "red"] [] ]

        symAndUse = 
            [ symbol [id "sym01"] justCirc
            , use [xlinkHref "#sym01", x "0", y "0", width "100", height "100"] []
            ]
    in
        svg [ viewBox "0 0 200 200", width "600px" ]
        --justCirc
        symAndUse


-- SETUP

main = Html.program { init = init, view = view, update = update, subscriptions = subscriptions }

type alias Model = Time

init : (Model, Cmd Msg)
init =
  (0, Cmd.none)

type Msg = Tick Time

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Tick newTime -> (0, Cmd.none)

subscriptions : Model -> Sub Msg
subscriptions model =
  AnimationFrame.times Tick

Original Comment:

SSCCE here

If you profile this example using the Chrome timeline, you can see that the browser is recalculating styles on every animation frame. Since the DOM isn't changing at all, this shouldn't be the case?
If you were to replace the last line symAndUse with justCirc, it does work as expected (no calculating restyles).

@process-bot
Copy link

Thanks for the issue! Make sure it satisfies this checklist. My human colleagues will appreciate it!

Here is what to expect next, and if anyone wants to comment, keep these things in mind.

@evancz evancz changed the title xlink:href breaking the elm virtual dom diffing Using xlink:href in SVG can cause pointless style recalculations Jul 7, 2017
@anka-213
Copy link

I believe the reason for this issue is that for all namespaced attributes the value is an object,

var _VirtualDom_attributeNS = F3(function(namespace, key, value)
{
return {
$: 'a__1_ATTR_NS',
__key: key,
__value: { __namespace: namespace, __value: value }
};
});

which we then try to compare by reference.

// reference equal, so don't worry about it
if (xValue === yValue && xKey !== 'value' && xKey !== 'checked'
|| category === 'a__1_EVENT' && _VirtualDom_equalEvents(xValue, yValue))

This is bound to fail and force a patch every time we do a comparison on namespaced attributes.


It seems like Firefox is kinder when you use setAttributeNS with the old value, while Chrome forces a recalculation and will even try to re-fetch images from the network (see evancz/elm-playground#5 for an example).

@anka-213
Copy link

anka-213 commented Sep 19, 2019

Adding a condition like this

 if (xValue === yValue && xKey !== 'value' && xKey !== 'checked' 
 	|| category === 'a__1_EVENT' && _VirtualDom_equalEvents(xValue, yValue)
        || category === 'a__1_ATTR_NS' && xValue.__namespace === yValue.__namespace && xValue.__value === yValue.__value)

to the if-clause in _VirtualDom_diffFacts should solve the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants