Skip to content

Instantly share code, notes, and snippets.

@LynnAU
Created April 19, 2018 10:40
Show Gist options
  • Save LynnAU/2fb22c94b3b5dbc29f0c0549cf83c81a to your computer and use it in GitHub Desktop.
Save LynnAU/2fb22c94b3b5dbc29f0c0549cf83c81a to your computer and use it in GitHub Desktop.
A react version of https://codepen.io/andyNroses/pen/AXwPkb . The style is slightly different to the codepen but the values can be moved over, it's basically the same code in a slightly different format and structure
.menu {
width: 40px;
height: 40px;
}
.center {
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.item {
position: absolute;
left: 0px;
top: 0px;
width: 50px;
height: 50px;
background-color: white;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
cursor: pointer;
vertical-align: middle;
text-align: center;
line-height: 50px;
}
import React, { Component } from 'react';
import anime from 'animejs';
import $ from 'jquery';
import 'jquery-ui-dist/jquery-ui';
import 'jquery-ui-dist/jquery-ui.css';
import './Nav.css';
window.timeOut = undefined;
export default class Nav extends Component {
Add(item) {
let menu = this;
if(!this.first) {
this.first = this.last = item;
this.first.$element.on('mouseup', () => {
if(menu.first.isMoving) menu.first.isMoving = false;
else menu.Click();
});
item.$element.draggable(
{
start: () => {
menu.Close();
item.isMoving = true;
}
},
{
drag: () => {
if(item.next) item.next.UpdatePosition();
}
},
{
stop: () => {
item.isMoving = false;
item.MoveTo(item);
}
}
);
} else {
this.last.next = item;
item.prev = this.last;
this.last = item;
}
return item;
}
Open() {
this.status = 'open';
let current = this.first.next,
head = this.first,
temp = this.first.next,
numOfNodes = 0,
radius = 110,
angle = 0;
while(temp !== null) { numOfNodes++; temp = temp.next; }
let step = (2 * Math.PI) / numOfNodes;
radius = 20 * numOfNodes;
while(current !== null) {
anime({
targets: current.$element[0],
left: parseInt(head.$element.css('left'), 10) + Math.round(radius * Math.cos(angle)),
top: parseInt(head.$element.css('top'), 10) + Math.round(radius * Math.sin(angle)),
duration: 500
});
current = current.next;
angle += step;
}
}
Close() {
this.status = 'closed';
let current = this.first.next,
head = this.first;
while(current !== null) {
anime({
targets: current.$element[0],
left: head.$element.css('left'),
top: head.$element.css('top'),
duration: 500
});
current = current.next;
}
}
Click() {
if(this.status === 'closed') this.Open();
else this.Close();
}
constructor(opts) {
super(opts);
this.state = {
size: 0,
tabs: []
};
this.$element = this.first = this.last = null;
this.status = 'closed';
this.Add = this.Add.bind(this);
this.Open = this.Open.bind(this);
this.Close = this.Close.bind(this);
this.Click = this.Click.bind(this);
}
componentDidMount() {
let tabs = [];
this.props.tabs.forEach((tab, index) => tabs.push(<Item key={tab.id} {...tab} order={index} numOfTabs={this.props.tabs.length} RegisterNewItem={this.Add} />));
this.setState({
tabs: [ ...this.state.tabs, tabs ]
});
$('[data-toggle="tooltip"]').tooltip();
console.log(this);
}
render() {
return (
<div className="menu center">
<div id={this.props.element} ref={ele => this.$element = $(ele)}>
{ this.state.tabs }
</div>
</div>
);
}
}
class Item extends Component {
componentDidMount() {
this.props.RegisterNewItem(this);
let element = this;
this.$element.on('mousemove', () => {
clearTimeout(window.timeOut);
window.timeOut = setTimeout(() => element.next && element.isMoving ? element.next.MoveTo(element) : null, 10);
});
if(this.props.onMount) this.props.onMount();
}
MoveTo(item) {
anime({
targets: this.$element[0],
left: item.$element.css('left'),
top: item.$element.css('top'),
duration: 700,
elasticity: 500
});
if(this.next) this.next.MoveTo(item);
}
UpdatePosition() {
anime({
targets: this.$element[0],
left: this.prev.$element.css('left'),
top: this.prev.$element.css('top'),
duration: 200
});
if(this.next) this.next.UpdatePosition();
}
constructor(opts) {
super(opts);
this.prev = this.next = null;
this.isMoving = false;
}
render() {
return (
<div className="item" style={{backgroundColor:this.props.bgColour,zIndex:(this.props.numOfTabs - this.props.order)}} data-toggle="tooltip" data-placement="left" title={this.props.tooltip} onClick={this.props.onClick} ref={ele => { this.$element = $(ele); }}>
<i className={this.props.icon} style={{color:this.props.colour}} />
{ this.props.innerHTML }
</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment