Code Monkey home page Code Monkey logo

react-svg-morph's Introduction

React svg morph

morph your svg components one into another

React Icons

Instalation

npm install react-svg-morph --save

Usage example

import React from 'react';
import ReactDOM from 'react-dom';
import { MorphReplace } from 'react-svg-morph';

class Checked extends React.Component {
    render() {
        return (
            <svg width="24" fill="#00ea00" height="24" viewBox="0 0 24 24">
                <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
            </svg>
        );
    }
}

class CheckBox extends React.Component {
    render() {
        return (
            <svg width="24" height="24" fill="#666666" viewBox="0 0 24 24">
                <path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/>
            </svg>
        );
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            checked: false
        };
    }
    toggleChecked() {
        this.setState({checked: !this.state.checked});
    }
    render() {
        return (
            <div onClick={this.toggleChecked.bind(this)}>
                <MorphReplace width={100} height={100}>
                    {this.state.checked ? <Checked key="checked" /> : <CheckBox key="checkbox" />}
                </MorphReplace>
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('app'));

Usage with react-native

react-svg-morph only works on ios because react native art package is only available there. Before getting started you will need to include ReactNativeArt into your project, there is good example how to do that on this link http://browniefed.com/blog/2015/05/03/getting-react-art-running-on-react-native/

Everything else is the same only you need to include MorphReplaceNative and MorphTransitionNative from react-svg-morph/native.

For now it works with normal svg tags/components like in example top.

API

<MorphReplace /> or <MorphReplaceNative />

when children element change it will morph from one svg element into another svg element Props:

width: Number

width of the svg element defaults to 40

height: Number

height of the svg element defaults to 40

viewBox: String

viewBox of the svg element default to 0 0 ${width} ${height}

duration: Number

swap animation duration in ms defaults to 350 ms

rotation: String

rotation of the animation available options are clockwise, counterclock, none defaults to clockwise

preserveAspectRatio: String

Attribute preserveAspectRatio indicates whether or not to force uniform scaling. For available options look here. Default value is xMidYMid meet.

easing: function

easing function, default easing is linear

/*
 * Easing Functions - inspired from http://gizma.com/easing/
 * only considering the t value for the range [0, 1] => [0, 1]
 */
var easeInCubic = function(t) {
    return t*t*t;
}

there is default easing functions already provided in src/utils/easing or lib/utils/easing so you can reuse them

import {easeInQuint} from `lib/utils/easing`
<MorphReplace easing={easeInQuint}>
    {this.state.checked ? <Checked /> : <CheckBox />}
</MorphReplace>

children: React.Element

only element you want to display need to be passed as children, when you replace that element with new one animation will be triggered. It's important to provide key prop to child element so MorphReplace know when child is changed.

every other props passed to the element will be passed to svg, so you can also pass normal svg attributes like fill,opaticy,styles...

usage example
import {MorphReplace} from 'react-svg-morph';

render() {
    return (
        <MorphReplace width={100} height={100}>
            {this.state.checked ? <Checked key={'checked'} /> : <CheckBox key={'checkbox'}/>}
        </MorphReplace>
    )
}

<MorphReplaceResize />

same as MorphReplace only you should use this when you have two svg elements that have different viewBox attributes so MorphReplaceResize will normalize their paths before passing it to MorphReplace

<MorphTransition /> or <MorphTransitionNative />

width: Number

width of the svg element defaults to 40

height: Number

height of the svg element defaults to 40

viewBox: String

viewBox of the svg element default to 0 0 ${width} ${height}

viewBox is ignored in react-native

progress: Number

current progress of the svg animation, default to 0

rotation: String

rotation of the animation available options are clockwise, counterclock, none defaults to clockwise

every other props passed to the element will be passed to svg, so you can passs normal svg attributes like fill,opaticy,styles...

children: Object{from: React.Element, to: React.Element}

accept two React elements that need to have svg element inside, it will morph one into another based on progress passed

other props

All other props will be passed to the svg element

usage example
import {MorphTransition} from 'react-svg-morph';

render() {
    return (
        <MorphTransition progres={50} width={100} height={100}>
            {from: <LoveSvg />, to: <LogoSvg />}
        </MorphReplace>
    )
}

it can be also used with react-motion

Related

  • it works with react-icons out of the box because they are all normalized to the same size

License

MIT Copyright (c) Goran Gajic 2015

Credits

svg convert algorithm is adopted from https://github.com/alexk111/SVG-Morpheus.

react-svg-morph's People

Contributors

conorhastings avatar evenchange4 avatar gorangajic avatar hairyrabbit avatar infiman avatar npmcdn-to-unpkg-bot avatar nufflee avatar sebt avatar suhaotian avatar wuct avatar xesrevinu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-svg-morph's Issues

Add possibility to set "preserveAspectRatio" for svg

Hi there,

I have a problem with resizing of my SVG image while using your package. preserveAspectRatio attribute allows you to tell from which anchor point to scale, but inside of your implementation this attribute is hardcoded to preserveAspectRatio="xMidYMid meet". I have an idea to create a pull request to fix it and start passing this attribute as a prop. What do you think?

Thank you,
Igor

SVG rendering glitch.

Hey there! I hate to be a bother, but I just tried to implement this component in a project I'm working on and ran into an SVG rendering glitch. I was hoping you might have some insight into what I might have gotten wrong.

nt0ujgq7sk

The first SVG renders as expected, but after the transition, the second one---which should be an โจ‰---looks a little corrupted. I'm not sure how to go about troubleshooting this, but I'm happy to provide any details that'd be useful.

Here's the component I was writing, in case it helps:

import {MorphReplace} from 'react-svg-morph';
import {easeInQuint} from 'react-svg-morph/lib/utils/easing';
import styles from './styles';

class MenuButton extends React.Component {
  static propTypes = {
    menuOpen: React.PropTypes.bool,
    onClick: React.PropTypes.func
  };

  render() {
    const {
      menuOpen,
      onClick
    } = this.props;

    return (
      <div className={styles.button} onClick={onClick}>
        <MorphReplace easing={easeInQuint} height={24} width={24}>
          {menuOpen
            ? <svg height="24" key="close" viewBox="0 0 24 24" width="24">
                <path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" />
              </svg>
            : <svg height="24" key="menu" viewBox="0 0 24 24" width="24">
                <path d="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z" />
              </svg>
          }
        </MorphReplace>
      </div>
    );
  }
}

export default MenuButton;

I saw similar results when I refactored the <svg> tags out into separate React components, so I suspect that's not it. Otherwise... any thoughts? Thanks in advance!

easing function with MorphReplace

Can i change the easing function in MorphReplace?

i have this code but not work...

import { MorphReplace } from 'react-svg-morph';
import { easeInOutCubic } from 'react-svg-morph/lib/utils/easing';

renderLine() {
    return (
      <MorphReplace
        easing={easeInOutCubic}
        width={100}
        height={100}
        duration={1000}
        rotation="none"
      >
        {this.state.isOpen ? <OpenCurvedSVG key="open" /> : <LineSVG key="close" />}
      </MorphReplace>
    );
  }

Trivial example of using MorphReplace alongisde with react-icons is no longer working

Hi, I'm trying to adapt the example displayed on the ReadMe in order to make it simply work with react-icons since it's claimed to be working with this library.

A change in either react-svg-morph or react-icons might have made both libraries to be incompatible.

I'm testing out the following basic snippet :

import React from "react";
import { MorphReplace } from "react-svg-morph";
import {
  FaRegPauseCircle as PauseIcon,
  FaRegPlayCircle as PlayIcon
} from "react-icons/fa";
import "./styles.css";

export default class App extends React.Component {
  state = {};

  componentDidMount() {
    setInterval(() => {
      this.setState({
        pause: !this.state.pause
      });
    }, 1000);
  }

  render() {
    const { pause } = this.state;

    return (
      <MorphReplace width={50} height={50}>
        {pause ? <PauseIcon key={"checked"} /> : <PlayIcon key={"checkbox"} />}
      </MorphReplace>
    );
  }
}

Using this trivial code will lead to a TypeError exception to be thrown :

"Component is not function" error
renderToJson
https://vuv3l.csb.app/node_modules/react-render-to-json/lib/renderToJson.js:29:24

Which seems to be inherent to the ReactDOM.render() call.

You might want to take a look at this sandbox to see the problem in action : https://codesandbox.io/s/charming-khayyam-vuv3l?file=/src/App.js

To make it work, a hack must currently be used :

import parse from 'html-react-parser';
import { renderToString } from 'react-dom/server';

export const getSVGElement =
  (content, key) => parse(renderToString(content).replace('<svg', `<svg key="${key}"`));

 <MorphReplace width={50} height={50}>
        {pause ? getSVGElement(<PlayIcon />, "playSVG") : getSVGElement(<PauseIcon />, "pauseSVG") }
      </MorphReplace>

Unsafe ComponentWill... lifecycle methods

Code at issue:
https://github.com/gorangajic/react-svg-morph/blob/master/src/MorphReplace.js#L26, among others.

More on this:

Syntactically speaking, the methods as you have implemented them currently will no longer function as of React 17. You will at least need to use the UNSAFE variants, although I recommend not using them at all, or just using componentDidUpdate.

this lib is dead

this library seems to be dead. no support for functional components either.
I'm currently seeking alternatives.

New className API

Thanks for this awesome lib. I want to suggest a new className API, by which we can pass down a className to <svg />.

For example:

<MorphReplace className="foo"/>

will generate

<svg className="foo">

I would like to open a PR for this, if the API looks good to you.

Invalid DOM property for dash-case SVG attributes, such as stroke-width

If your SVG component has properties like stroke-width, you get the following console warning.

Warning: Invalid DOM property `stroke-width`. Did you mean `strokeWidth`?
    in path (created by MorphTransition)
    in svg (created by MorphTransition)
    in MorphTransition (created by MorphReplace)
    in MorphReplace (created by App)
    in div (created by App)
    in App

It would seem strokeWidth (camelCase) should be used instead, but helpers.js and normalizeSvg.js expect the dash-case versions.

Is there a reason it doesn't use camelCase, as would seem more typical in React? Any idea on how to get rid of the warning?

Breaks use of context

If you have elements that expect to get context (e.g. theming), this is broken by wrapping them in MorphReplace. For example, I tried to use this with two SvgIcons from material-ui (which relies on a context-based theming model) and their context ends up undefined. Is there a way to make MorphReplace etc. "invisible", by ensuring that context gets passed through to the children as if it wasn't there?

ReactNative Android Support

Im lazy and have not tried yet... but one way or another this is an issue...

The ReadMe says iOS only because of no art support on android, but as of earlier this year thats not true. So does it work now, and the docs need updating? or is is broken and some compatibility issues exist?

Note: I know I'm lazy and will be testing it later this week if no one responds before then ๐Ÿ˜Š

Using react-svg-morph with react-icons

Hi, I have a problem making these two modules work together. I use pretty basic, that goes like this:

 const MobileIcon = showMenu ? ChevronLeft : Menu
 return (
                      <MorphReplace>
                                <MobileIcon/>
                       </MorphReplace>                       
        )

There is an error in renderToJsonMethod in particular this part fails with undefined render:

var instance = new Component(element.props);
    res.name = Component.name;
    children = instance.render();

I use the latest versions of both libraries.

It's not working for me. Thrown error: Expected a class but got undefined

I did tried 2 ways:

CancelSvg.js

import React from 'react'
import Svg, { Line } from 'react-native-svg'

export default class CancelSvg extends React.Component {
  render () {
    return (
      <Svg height='50' width='50'>
        <Line x1={37.5} x2={12.5} y1={12.5} y2={37.5} strokeWidth='2.5' stroke={'#fff'} />
        <Line x1={12.5} x2={37.5} y1={12.5} y2={37.5} strokeWidth='2.5' stroke={'#fff'} />
      </Svg>
    )
  }
}

MenuSvg.js

import React from 'react'
import Svg, { Line } from 'react-native-svg'

export default class MenuSvg extends React.Component {
  render () {
    return (
      <Svg height='50' width='50'>
        <Line x1={10} x2={40} y1={15} y2={15} strokeWidth='2.5' stroke={'#fff'} />
        <Line x1={10} x2={40} y1={25} y2={25} strokeWidth='2.5' stroke={'#fff'} />
        <Line x1={10} x2={40} y1={35} y2={35} strokeWidth='2.5' stroke={'#fff'} />
      </Svg>
    )
  }
}

Main.js

                <MorphReplaceNative width={60} height={60}>
                  {
                    this.state.showMenu ? <MenuSvg /> : <CancelSvg />
                  }
                </MorphReplaceNative>

Error: Expected a class but got undefined. You likely forgot to export your Component from the file it's defined.

But I did export it. I also tried replacing with in MenuSvg.js and CancelSvg.js but it's not working.

Basic example doesn't work

I copy pasted the example in the readme.
Clicking on the checkbox does not do anything

I'm using react 0.14.2. how can i trouble shoot this?

Show warning when key is not provided

Hi,
Just tried to repeat your example with a pair of MdFavoriteBorder/MdFavorite and toggling active state by Click.
Console log confirms this.state.active is changed by click, but icon change not happen. (((

import { MorphReplace } from 'react-svg-morph';
import MdFavoriteBorder from 'react-icons/lib/md/favorite-border';
import MdFavorite from 'react-icons/lib/md/favorite';

toggleChecked: function() {
    this.setState({active: !this.state.active});
  },
  render() {
    var icon;
    if(this.state.active) {
      console.log("active");
      icon = <MdFavoriteBorder />;
    } else {
      console.log("passive");
      icon = <MdFavorite />;
    }
    return (
      <div onClick={this.toggleChecked} >
        <MorphReplace >
          { icon }
        </MorphReplace>
      </div>
    );
  }

Can't understand the reason.
Could you please help

Iho

Feature request: operate on specific elements in an svg

At the moment, attempting to morph inner svg elements gives an error. For example

<MorphReplace>
    <path
        key={this.pathKey}
        d={pathDefinition}
        className={curveStyles}
    />
</MorphReplace>

results in Uncaught TypeError: Cannot read property 'children' of undefined (caught in normizeSvg.js because findSvgRoot returns undefined).

Allowing this would be cool for applications such as data visualization. In my case animation is already handled for other svg elements and I just want to morph one particular path.

MorphReplace with more than 2 Icons

Hey,

I've got it working with two icons, but as soon as I add more, it stops working
I have an array of jsx elements and a counter in the state, hoping to use it as a loading indicator:

<MorphReplace width={size} height={size}> { icons[this.state.counter % icons.length] } </MorphReplace>

Any help with this?
thanks in advance

It's not work

I tried it in generator-react-webpack.It's not work.Thank you!

Properties like width and height are working,but neither animation nor icon changes while changing states.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.