question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SVG In ScrollView

See original GitHub issue

Hi,

I am trying to make a drawing app using React Native and this library. Here is my code:

import React from "react";
import { PanResponder, Alert, StyleSheet, View, Text } from "react-native";
import { G, Line, Svg, Path } from "react-native-svg";

class Drawing extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      offsetX: 0,
      offsetY: 0,
      width: "100%",
      height: "200",
      paths: [],
      currentPath: ""
    };
    this.layout.bind(this);
  }

  layout(event) {
    // Called when the board is rendered and frame dimensions are available
    this._board.measure((width, height, px, py, fx, fy) => {
      this.setState({
        offsetX: fx,
        offsetY: fy,
        width: px,
        height: py
      });
    });
  }

  componentWillMount() {
    // Simple equation to map a number within a range to another range
    Number.prototype.map = function(in_min, in_max, out_min, out_max) {
      return (
        (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
      );
    };
    let extractCoordinates = gestureState => {
      // Subtract offset from coordinate returned and map to viewBox range
      return {
        x: (gestureState.moveX - this.state.offsetX).map(
          0,
          this.state.width,
          0,
          720
        ),
        y: (gestureState.moveY - this.state.offsetY).map(
          0,
          this.state.height,
          0,
          1000
        )
      };
    };
    this._touchCatcher = PanResponder.create({
      onMoveShouldSetPanResponderCapture: (evt, gestureState) =>
        this.props.drawingEnabled,

      onPanResponderGrant: (event, gestureState) => {
        // Gesture started
        let point = extractCoordinates(gestureState);
        this.setState({
          currentPath: `M${point.x} ${point.y} `
        });
      },
      onPanResponderMove: (evt, gestureState) => {
        let point = extractCoordinates(gestureState);
        this.setState({
          currentPath: this.state.currentPath + `L${point.x} ${point.y} `
        });
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        // The user has released all touches while this view is the
        // responder. This typically means a gesture has succeeded
        this.setState({
          paths: [...this.state.paths, this.state.currentPath],
          currentPath: ""
        });
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // Another component has become the responder, so this gesture
        // should be cancelled
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // Returns whether this component should block native components from becoming the JS
        // responder. Returns true by default. Is currently only supported on android.
        return true;
      }
    });
  }

  render() {
    let pathElements = [];
    let i = 0;
    for (path of this.state.paths) {
      pathElements.push(<Path key={i} d={path} stroke="black" fill="none" strokeWidth="1" />);
      i++;
    }
    return (
      <View style={styles.border}>
        <View
          style={{
            width: "100%",
            height: "100%",
            backgroundColor: "white"
          }}
          ref={board => (this._board = board)}
          onLayout={e => this.layout(e)}
          {...this._touchCatcher.panHandlers}
        >
          <Svg
            width={this.state.width}
            height={this.state.height}
            key={this.state.paths.length}
            viewBox="0 0 720 1000"
          >
            <G>
              <Path
                d={this.state.currentPath}
                fill="none"
                stroke="black"
                strokeWidth={1}
              />
              {pathElements}
            </G>
          </Svg>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  border: {
    width: "100%",
    aspectRatio: 0.72,
    padding: "4%",
    backgroundColor: "#E57373",
    borderRadius: 10,
    shadowOpacity: 0.75,
    shadowRadius: 5,
    shadowColor: "grey",
    shadowOffset: { height: 8, width: 0 }
  },
  board: {
    width: "100%",
    height: "100%",
    backgroundColor: "white"
  }
});

export default Drawing;

The problem is that when I zoom in to draw on a particular section of the drawing, the path is very low resolution. I have looked into previous issues filed on how to force a re-render of the SVG, but as you can see I’m already using the key workaround and that doesn’t appear to be working. The only way I have found to trigger a refresh is to set the width and height to arbitrary values and then draw a path and then change them back to what they were before; but this is obviously not an ideal way to do this.

What should I be doing instead?

As a Swift developer I would say the easiest thing for you guys to do would be to implement a forceReload prop or something else so that the SVG is re-drawn every time a render is called. I could try doing this myself and filing a pull request, I would just need guidance on what files I should touch and what you guys think of my approach.

Thanks for all the work you’ve already put in!

- Andi

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:7

github_iconTop GitHub Comments

3reactions
msandcommented, Jan 19, 2018
2reactions
msandcommented, Feb 15, 2018

We had to use the same trick in https://infinitewhiteboard.com thought it might be useful for you as well 😄

Read more comments on GitHub >

github_iconTop Results From Across the Web

Svg element is not displayed inside ScrollView if I try to use ...
When I try this, the Svg element is displayed but then, the text that ends up outside the screen is outside the scrollview...
Read more >
Issue #578 · software-mansion/react-native-svg - GitHub
Hi, I am trying to make a drawing app using React Native and this library. Here is my code: import React from "react";...
Read more >
SVG and Scrollview - Expo Snack
SVG and Scrollview. No description. Open with Expo Go. Open in editor. Need Expo? Don't have the Expo Go? Download the app to...
Read more >
View Components Guide - Fitbit SDK
The scrollview component allows developers to create an application which is taller than the screen dimensions. The user can easily scroll the entire ......
Read more >
SVG Image in ScrollView - Webix Forum
The svg graphic is based on a graphviz DOT file, which is rendered with dagreD3 and the zooming is done with d3.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found