Giter Club home page Giter Club logo

reactpathmenu's Introduction

reactpathmenu's People

Contributors

arturgorski avatar kos-m avatar kyleamathews avatar mathew3 avatar nashvail 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

reactpathmenu's Issues

Update to React-motion 0.4.X

Recently I've been trying to update your code for react-motion 0.4.3.

Everything works fine except when I try to close the menu. Here a gif to show you what I have

I've managed to see that the reverse function made my problem.

Here is my attemp to make the upgrade.

'use strict';
import React from 'react';
import ReactDOM from 'react-dom';
import {Motion, StaggeredMotion, spring} from 'react-motion';
import range from 'lodash.range';

// Components

//Constants

// Diameter of the main button in pixels
const MAIN_BUTTON_DIAM = 90;
const CHILD_BUTTON_DIAM = 48;
// The number of child buttons that fly out from the main button
const NUM_CHILDREN = 5;
// Hard code the position values of the mainButton
const M_X = 490;
const M_Y = 450;

//should be between 0 and 0.5 (its maximum value is difference between scale in finalChildButtonStyles a
// nd initialChildButtonStyles)
// const OFFSET = 0.4;
const OFFSET = 0.05; //0.05 for a better view of the reverse bug

//Version 3.1 with array
//const SPRING_CONFIG = [400, 28];
// version 4.X uses object instead
const SPRING_CONFIG = {stiffness : 400, damping : 28};

// How far away from the main button does the child buttons go
const FLY_OUT_RADIUS = 130,
    SEPARATION_ANGLE = 40, //degrees
    FAN_ANGLE = (NUM_CHILDREN - 1) * SEPARATION_ANGLE, //degrees
    BASE_ANGLE = ((180 - FAN_ANGLE)/2); // degrees

// Names of icons for each button retreived from fontAwesome, we'll add a little extra just in case
// the NUM_CHILDREN is changed to a bigger value
let childButtonIcons = ['pencil', 'at', 'camera', 'bell', 'comment', 'bolt', 'ban', 'code'];


// Utility functions

function toRadians(degrees) {
    return degrees * 0.0174533;
}

function finalChildDeltaPositions(index) {
    let angle = BASE_ANGLE + (index* SEPARATION_ANGLE);
    return {
        deltaX: FLY_OUT_RADIUS * Math.cos(toRadians(angle)) - (CHILD_BUTTON_DIAM/2),
        deltaY: FLY_OUT_RADIUS * Math.sin(toRadians(angle)) + (CHILD_BUTTON_DIAM/2)
    };
}


class APP extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isOpen: false,
            childButtons: []
        };

        // Bind this to the functions
        this.toggleMenu = this.toggleMenu.bind(this);
        this.closeMenu = this.closeMenu.bind(this);
    }

    componentDidMount() {
        window.addEventListener('click', this.closeMenu);
        let childButtons = [];

        this.setState({childButtons: childButtons.slice(0)});
    }

    mainButtonStyles() {
        return {
            width: MAIN_BUTTON_DIAM,
            height: MAIN_BUTTON_DIAM,
            top: M_Y - (MAIN_BUTTON_DIAM/2),
            left: M_X - (MAIN_BUTTON_DIAM/2)
        };
    }

    initialChildButtonStyles() {
        return {
            width: CHILD_BUTTON_DIAM,
            height: CHILD_BUTTON_DIAM,
            top: spring(M_Y - (CHILD_BUTTON_DIAM/2), SPRING_CONFIG),
            left: spring(M_X - (CHILD_BUTTON_DIAM/2), SPRING_CONFIG),
            rotate: spring(-180, SPRING_CONFIG),
            scale: spring(0.5, SPRING_CONFIG)
        };
    }

    initialChildButtonStylesInit() {
        return {
            width: CHILD_BUTTON_DIAM,
            height: CHILD_BUTTON_DIAM,
            top: M_Y - (CHILD_BUTTON_DIAM/2),
            left: M_X - (CHILD_BUTTON_DIAM/2),
            rotate: -180,
            scale: 0.5
        };
    }

    finalChildButtonStylesInit(childIndex) {
        let {deltaX, deltaY} = finalChildDeltaPositions(childIndex);
        return {
            width: CHILD_BUTTON_DIAM,
            height: CHILD_BUTTON_DIAM,
            top: M_Y - deltaY,
            left: M_X + deltaX,
            rotate: 0,
            scale: 1
        };
    }

    finalChildButtonStyles(childIndex) {
        let {deltaX, deltaY} = finalChildDeltaPositions(childIndex);
        return {
            width: CHILD_BUTTON_DIAM,
            height: CHILD_BUTTON_DIAM,
            top: spring(M_Y - deltaY, SPRING_CONFIG),
            left: spring(M_X + deltaX, SPRING_CONFIG),
            rotate: spring(0, SPRING_CONFIG),
            scale: spring(1, SPRING_CONFIG)
        };
    }

    toggleMenu(e) {
        e.stopPropagation();
        let{isOpen} = this.state;
        this.setState({
            isOpen: !isOpen
        });
    }

    closeMenu() {
        this.setState({ isOpen: false});
    }

    renderChildButtons() {
        const {isOpen} = this.state;
        const targetButtonStylesInitObject = range(NUM_CHILDREN).map(i => {
            return isOpen ? this.finalChildButtonStylesInit(i) : this.initialChildButtonStylesInit();
        });

        //StaggeredMotion now takes an Array of object
        const targetButtonStylesInit = Object.keys(targetButtonStylesInitObject).map(key => targetButtonStylesInitObject[key]);

        const targetButtonStyles = range(NUM_CHILDREN).map(i => {
            return isOpen ? this.finalChildButtonStyles(i) : this.initialChildButtonStyles();
        });

        const scaleMin = this.initialChildButtonStyles().scale.val;
        const scaleMax = this.finalChildButtonStyles(0).scale.val;

        let calculateStylesForNextFrame = prevFrameStyles => {
             prevFrameStyles = isOpen ? prevFrameStyles : prevFrameStyles.reverse();
            //prevFrameStyles = isOpen ? prevFrameStyles : prevFrameStyles;

            let nextFrameTargetStyles =  prevFrameStyles.map((buttonStyleInPreviousFrame, i) => {
                //animation always starts from first button
                if (i === 0) {
                    return targetButtonStyles[i];
                }

                const prevButtonScale = prevFrameStyles[i - 1].scale;
                const shouldApplyTargetStyle = () => {
                    if (isOpen) {
                        return prevButtonScale >= scaleMin + OFFSET;
                    } else {
                        return prevButtonScale <= scaleMax - OFFSET;
                    }
                };

                return shouldApplyTargetStyle() ? targetButtonStyles[i] : buttonStyleInPreviousFrame;
            });

            return isOpen ? nextFrameTargetStyles : nextFrameTargetStyles.reverse();
            // return isOpen ? nextFrameTargetStyles : nextFrameTargetStyles;
        };

        return (
            <StaggeredMotion
                defaultStyles={targetButtonStylesInit}
                styles={calculateStylesForNextFrame}>
                {interpolatedStyles =>
                    <div>
                        {interpolatedStyles.map(({height, left, rotate, scale, top, width}, index) =>
                            <div
                                className="child-button"
                                key={index}
                                style={{
                                    left,
                                    height,
                                    top,
                                    transform: `rotate(${rotate}deg) scale(${scale})`,
                                    width
                                }}
                            >
                                <i className={"fa fa-" + childButtonIcons[index] + " fa-lg"}></i>
                            </div>
                        )}
                    </div>
                }
            </StaggeredMotion>
        );
    }

    render() {
        let {isOpen} = this.state;
        let mainButtonRotation = isOpen ? {rotate: spring(0, {stiffness : 500, damping : 30})} : {rotate: spring(-135, {stiffness : 500, damping : 30})};
        return (
            <div>
                {this.renderChildButtons()}
                <Motion style={mainButtonRotation}>
                    {({rotate}) =>
                        <div
                            className="main-button"
                            style={{...this.mainButtonStyles(), transform: `rotate(${rotate}deg)`}}
                            onClick={this.toggleMenu}>
                            {/*Using fa-close instead of fa-plus because fa-plus doesn't center properly*/}
                            <i className="fa fa-close fa-3x"/>
                        </div>
                    }
                </Motion>
            </div>
        );
    }
};

module.exports = APP;

Add an Open Source Licence?

Hi Nash,
I have read your blog post and this is exactly what I was looking to build, too. I would be really happy to use your component in my open source project, but the corporate restrictions prevent me from doing so if the product has no licence. Could you add one?
Greetings, Tim

New version closes wrong

I'm running chrome 53 on windows.
When I close the demo child buttons group together on the left and then come to the center.

I mean this:
sem titulo

Online Demo please?

Hi-
Really liked your article - how you explained the thinking, and all the embedded gifs to illustrate the nuances. Do you think there could be a GH pages demo? Would like to link to it from react.rocks.
Thanks!

New version broken, example does not work anymore

First of all thanks for this great component. I'm using the old version in my app and it works perfectly.

I tried to upgrade to the new version which uses [email protected]+, but it does not work as expected. The expand animation is OK, but collapse does not work properly, small buttons are not collapsed in the right sequence.

Also the example does not work anymore, there is an error

Warning: Failed prop type: Invalid prop `defaultStyles[0].top` of type `object` supplied to `StaggeredMotion`, expected `number`.
    in StaggeredMotion (created by APP)
    in APP

Just wanted to let you know. When I find some time, I will try to make it work with the latest version of react-motion.

I want to connect main button with child buttons

Thanks for great codes!
It is very useful for my project !!!
I have one question.

I want to connect the main button with child buttons by the line (seems like it is the node).

But I have no idea how to do.

Can anyone give me some advice?

like this....... โ†“

img_3482

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.