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

v10 regression - Animated view translation inside Svg tag #1247

Closed
sebqq opened this issue Jan 9, 2020 · 10 comments
Closed

v10 regression - Animated view translation inside Svg tag #1247

sebqq opened this issue Jan 9, 2020 · 10 comments

Comments

@sebqq
Copy link

sebqq commented Jan 9, 2020

Hello there.

I've found a regression in my code after upgrade to react-native-svg@^10.0.0 from version 9.13.6.

So basically if there is any Non SVG animated View (I'm using reanimated) located inside <Svg></Svg> component then I'm not able to change it's (Views) translateX and translateY value using style={{transform: [{translateX: somthingX}, {translateY: somethingY}]} property.

I'm not able to provide reproducible demo right now but I will add it later (probably after January).

My code goes like:

 // View is located inside because it's position is computed by 
 // Line's x/y position and TexInput is always centered on the line
<Svg style={StyleSheet.absoluteFill}>
  <Animated.View
    style={[
      styles.textInputContainer,
      {
        opacity: textVisible,
        transform: [{ translateX: textX }, { translateY: textY }] // this is not working
      }
    ]}
    >
    <TextInput
        ref={distanceRef} // using setNativeProps to change text...
        maxFontSizeMultiplier={0}
        editable={false}
        style={styles.textInput}
     />
  </Animated.View>
  <ALine // ALine is just Animated.createAnimatedComponent(Line)
    x1={x1}
    y1={y1}
    x2={x2}
    y2={y2}
    stroke="#fff"
    strokeDasharray={[2, 7]}
    strokeOpacity="0.5"
    strokeWidth="2"
  />
</Svg>

I have the same problem at the other place in my code where is not set to be positioned absolutely and I have there statically set width/height of Svg and I'm getting same result.

Hopefully somebody encountered same issue and can help with reproducible demo.

Have a nice day and thank you so much!

@msand
Copy link
Collaborator

msand commented Jan 9, 2020

Can you try wrapping the Animated.View with an AnimatedG and set the transform style on that instead?
something like this:

import {Svg,Line,G} from 'react-native-svg;
const AnimatedG = Animated.createAnimatedComponent(G);
...


<Svg style={StyleSheet.absoluteFill}>
  <AnimatedG 
    style={{
      opacity: textVisible,
      transform: [{ translateX: textX }, { translateY: textY }]
    }}>
  <Animated.View
    style={[
      styles.textInputContainer,
      {
        opacity: textVisible,
      }
    ]}
    >
    <TextInput
        ref={distanceRef} // using setNativeProps to change text...
        maxFontSizeMultiplier={0}
        editable={false}
        style={styles.textInput}
     />
  </Animated.View>
  </AnimatedG>
  <ALine // ALine is just Animated.createAnimatedComponent(Line)
    x1={x1}
    y1={y1}
    x2={x2}
    y2={y2}
    stroke="#fff"
    strokeDasharray={[2, 7]}
    strokeOpacity="0.5"
    strokeWidth="2"
  />
</Svg>

@msand
Copy link
Collaborator

msand commented Jan 9, 2020

This is actually the reason for making it a breaking change

@sebqq
Copy link
Author

sebqq commented Jan 10, 2020

Hello @msand and thank you for quick response!

Sadly I'm not able to make it work even using G component :(

Current code looks like:

<Svg style={StyleSheet.absoluteFill}>
      <AnimatedG
        style={{
          opacity: textVisible,
          transform: [{ translateX: textX }, { translateY: textY }]
        }}
      >
        <Animated.View style={styles.textInputContainer}>
          <TextInput
            ref={distanceRef}
            maxFontSizeMultiplier={0}
            editable={false}
            style={styles.textInput}
          />
        </Animated.View>
      </AnimatedG>
      <ALine
        x1={x1}
        y1={y1}
        x2={x2}
        y2={y2}
        stroke={colors.white}
        strokeDasharray={[2, 7]}
        strokeOpacity="0.5"
        strokeWidth="2"
      />
    </Svg>

Anyway, I've found that whenever code is changed and app is fast-refreshed (component is re-rendered), then my TextInput appears on the spot where it should be located :D

@sebqq
Copy link
Author

sebqq commented Jan 10, 2020

@msand Somehow my code is working now for iOS but there there is not TextInput displayed at all on Android :D

Enclosing my current code at other place in code where Image is not visible at all:

import React from "react";
import Animated, { Easing } from "react-native-reanimated";
import { G } from "react-native-svg";

const AnimatedG = Animated.createAnimatedComponent(G);
const MovableAvatar = ({ source, x, y }) => {
 ...

  return (
    <AnimatedG
      style={{
        transform: [{ translateX: x }, { translateY: y }]
      }}
    >
      <Image source={source} style={styles.avatar} />
    </AnimatedG>
  );
};

@msand
Copy link
Collaborator

msand commented Jan 18, 2020

Can you try this with v11 ?

import * as React from "react";
import { View, StyleSheet, TextInput } from "react-native";
import { Svg, Line, ForeignObject } from "react-native-svg";
import Animated, { Easing } from "react-native-reanimated";

const AnimatedForeignObject = Animated.createAnimatedComponent(ForeignObject);

const {
  set,
  cond,
  eq,
  and,
  startClock,
  clockRunning,
  block,
  timing,
  Value,
  Clock,
  interpolate
} = Animated;

function runTiming(clock, value, dest) {
  const state = {
    finished: new Value(1),
    position: new Value(value),
    time: new Value(0),
    frameTime: new Value(0)
  };

  const config = {
    duration: 500,
    toValue: new Value(0),
    easing: Easing.inOut(Easing.ease)
  };

  const reset = [
    set(state.finished, 0),
    set(state.time, 0),
    set(state.frameTime, 0)
  ];

  return block([
    cond(and(state.finished, eq(state.position, value)), [
      ...reset,
      set(config.toValue, dest)
    ]),
    cond(and(state.finished, eq(state.position, dest)), [
      ...reset,
      set(config.toValue, value)
    ]),
    cond(clockRunning(clock), 0, startClock(clock)),
    timing(clock, state, config),
    state.position
  ]);
}

export default class App extends React.Component {
  constructor(props) {
    super(props);
    const clock = new Clock();
    const base = runTiming(clock, -1, 1);
    this.anim = interpolate(base, {
      inputRange: [-1, 1],
      outputRange: [-100, 100]
    });
  }
  render() {
    return (
      <View style={styles.container}>
        <Svg width="100%" height="100%">
          <AnimatedForeignObject
            style={[
              {
                transform: [
                  { translateX: this.anim },
                  { translateY: this.anim }
                ]
              }
            ]}
          >
            <Animated.View style={[styles.textInputContainer]}>
              <TextInput style={styles.textInput} defaultValue="Testing" />
            </Animated.View>
          </AnimatedForeignObject>
          <Line
            x1={0}
            y1={0}
            x2="100%"
            y2="100%"
            stroke="blue"
            strokeDasharray={[2, 7]}
            strokeOpacity="0.5"
            strokeWidth="2"
          />
        </Svg>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    backgroundColor: "#ecf0f1",
    padding: 8
  },
  textInputContainer: {
    backgroundColor: "#c7f1c7",
    width: "100%",
    height: 100
  },
  textInput: {
    backgroundColor: "#b7d1f1",
    margin: 10,
    flex: 1,
  }
});

@sebqq
Copy link
Author

sebqq commented Jan 20, 2020

Thank you @msand it works now!

@sebqq sebqq closed this as completed Jan 20, 2020
@sebqq
Copy link
Author

sebqq commented Jan 20, 2020

Ok so after a bit of testing I can see a big performance regression using the most recent version of the library :( Using 9.13.6, my UI thread FPS doesn't drop and stays at 60 all the time (on iOS).

With v11 my FPS drops to 27-30 (on iOS).

For now, I will stay with v9.13.6 and I will leave this issue opened.

Hopefully I will add reproducible demo in a meantime.

@sebqq sebqq reopened this Jan 20, 2020
@msand
Copy link
Collaborator

msand commented Jan 20, 2020

I think we'll need to isolate the embedding of react-native components to foreignObject, not sure how to get it to render correctly on ios without the performance regressing workaround otherwise.

msand added a commit that referenced this issue Mar 4, 2020
Fixes performance regressions on ios
Place elements inside ForeignObject to use v10 / standard behaviour
ForeignObject should behave unchanged from v10 / v11

Possibly fixes #1258 as well

BREAKING CHANGE: Behavior of native elements is reverted to pre v10
msand pushed a commit that referenced this issue Mar 4, 2020
# [12.0.0](v11.0.1...v12.0.0) (2020-03-04)

* fix!: #1262 default width and height on svg ([1d6798b](1d6798b)), closes [#1262](#1262)
* fix!: #1247 Animated view translation inside Svg tag ([0288d95](0288d95)), closes [#1247](#1247) [#1258](#1258)

### Bug Fixes

* **ios:** handle gradient and pattern transform when null ([715e9b8](715e9b8))
* **ios:** pod install error ([675df92](675df92))
* **web:** [#1274](#1274) Unable to build using babel-plugin-react-native-web ([80b5064](80b5064))
* removed missing unnecessary React headers import error caused by non-framework style import ([f795029](f795029))

### Performance Improvements

* optimize extraction of fill, stroke, responder, matrix & display ([279c3fc](279c3fc))
* optimize handling of font properties in G elements ([0fa4177](0fa4177))
* optimize handling of inherited styles ([363c1b4](363c1b4))
* optimize svg root prop handling, simplify element development ([f0cd11d](f0cd11d))

### BREAKING CHANGES

* default size might change if width or height is missing
* Behavior of native elements is reverted to pre v10
@msand
Copy link
Collaborator

msand commented Mar 8, 2020

Reverted the logic to pre v10 state in v12, closing now. Please reply if you're still having issues.

@msand msand closed this as completed Mar 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants