2017-06-04 10:40:14 +08:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2017-03-23 07:24:36 +08:00
|
|
|
import { findDOMNode } from 'react-dom';
|
2016-07-16 04:45:54 +08:00
|
|
|
|
|
|
|
const propTypes = {
|
2017-06-03 03:25:02 +08:00
|
|
|
// Width of the view box
|
2016-07-18 23:30:04 +08:00
|
|
|
viewBoxWidth: PropTypes.number.isRequired,
|
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
// Height of the view box
|
2016-07-18 23:30:04 +08:00
|
|
|
viewBoxHeight: PropTypes.number.isRequired,
|
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
// x Position of the view box
|
2016-07-18 23:30:04 +08:00
|
|
|
viewBoxX: PropTypes.number.isRequired,
|
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
// y Position of the view box
|
2016-07-18 23:30:04 +08:00
|
|
|
viewBoxY: PropTypes.number.isRequired,
|
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
// Defines the cursor x position
|
2016-07-18 23:30:04 +08:00
|
|
|
cursorX: PropTypes.number.isRequired,
|
2016-07-16 04:45:54 +08:00
|
|
|
|
2017-06-03 03:25:02 +08:00
|
|
|
// Defines the cursor y position
|
2016-07-18 23:30:04 +08:00
|
|
|
cursorY: PropTypes.number.isRequired,
|
2016-07-16 04:45:54 +08:00
|
|
|
|
2017-06-08 04:29:35 +08:00
|
|
|
// Slide to view box width ratio
|
2017-04-28 06:21:04 +08:00
|
|
|
widthRatio: PropTypes.number.isRequired,
|
|
|
|
|
2017-06-08 04:29:35 +08:00
|
|
|
// Slide physical size to original size ratio
|
2017-04-28 06:21:04 +08:00
|
|
|
physicalWidthRatio: PropTypes.number.isRequired,
|
|
|
|
|
2016-07-16 04:45:54 +08:00
|
|
|
/**
|
|
|
|
* Defines the cursor fill colour
|
|
|
|
* @defaultValue 'red'
|
|
|
|
*/
|
|
|
|
fill: PropTypes.string,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines the cursor radius
|
|
|
|
* @defaultValue 5
|
|
|
|
*/
|
|
|
|
radius: PropTypes.number,
|
|
|
|
};
|
|
|
|
|
|
|
|
const defaultProps = {
|
|
|
|
fill: 'red',
|
|
|
|
radius: 5,
|
|
|
|
};
|
|
|
|
|
|
|
|
export default class Cursor extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2017-03-23 07:24:36 +08:00
|
|
|
this.state = {
|
2017-04-28 06:21:04 +08:00
|
|
|
prevData: undefined,
|
|
|
|
currentData: undefined,
|
|
|
|
defaultRadius: 5,
|
|
|
|
};
|
2017-03-23 07:24:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillMount() {
|
|
|
|
let calculatedData = this.calculatePositionAndRadius(this.props);
|
|
|
|
this.setState({
|
|
|
|
currentData: calculatedData,
|
|
|
|
prevData: calculatedData,
|
2017-04-28 06:21:04 +08:00
|
|
|
defaultRadius: calculatedData.finalRadius,
|
2017-03-23 07:24:36 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
|
|
let calculatedData = this.calculatePositionAndRadius(nextProps);
|
|
|
|
this.setState({
|
|
|
|
prevData: this.state.currentData,
|
|
|
|
currentData: calculatedData,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
2017-04-28 06:21:04 +08:00
|
|
|
const { cursorCoordinates, cursorRadius } = this.refs;
|
|
|
|
var node1 = findDOMNode(cursorCoordinates);
|
|
|
|
var node2 = findDOMNode(cursorRadius);
|
|
|
|
node1.beginElement();
|
|
|
|
node2.beginElement();
|
2017-03-23 07:24:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
calculatePositionAndRadius(propsObj) {
|
|
|
|
return {
|
|
|
|
//Adjust the x,y cursor position according to zoom
|
|
|
|
cx: (propsObj.cursorX * propsObj.viewBoxWidth) + propsObj.viewBoxX,
|
|
|
|
cy: (propsObj.cursorY * propsObj.viewBoxHeight) + propsObj.viewBoxY,
|
|
|
|
//Adjust the radius of the cursor according to zoom
|
2017-04-28 06:21:04 +08:00
|
|
|
//and divide it by the physicalWidth ratio, so that svg scaling wasn't applied to the cursor
|
|
|
|
finalRadius: (propsObj.radius * propsObj.widthRatio / 100) / this.props.physicalWidthRatio,
|
2017-03-23 07:24:36 +08:00
|
|
|
fill: propsObj.fill,
|
|
|
|
}
|
2016-07-16 04:45:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const {
|
2017-03-23 07:24:36 +08:00
|
|
|
currentData,
|
|
|
|
prevData
|
|
|
|
} = this.state;
|
2016-07-16 04:45:54 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<circle
|
2017-04-28 06:21:04 +08:00
|
|
|
r={this.state.defaultRadius}
|
2017-03-23 07:24:36 +08:00
|
|
|
fill={currentData.fill}
|
|
|
|
>
|
|
|
|
<animateTransform
|
2017-04-28 06:21:04 +08:00
|
|
|
ref="cursorCoordinates"
|
2017-03-23 07:24:36 +08:00
|
|
|
attributeName="transform"
|
|
|
|
type="translate"
|
|
|
|
from={prevData.cx + " " + prevData.cy}
|
|
|
|
to={currentData.cx + " " + currentData.cy}
|
|
|
|
begin={'indefinite'}
|
|
|
|
dur="0.1s"
|
|
|
|
repeatCount="0"
|
|
|
|
fill="freeze"
|
|
|
|
/>
|
2017-04-28 06:21:04 +08:00
|
|
|
<animate
|
|
|
|
ref="cursorRadius"
|
|
|
|
attributeName="r"
|
|
|
|
attributeType="XML"
|
|
|
|
from={prevData.finalRadius}
|
|
|
|
to={currentData.finalRadius}
|
|
|
|
begin={'indefinite'}
|
|
|
|
dur="0.2s"
|
|
|
|
repeatCount="0"
|
|
|
|
fill="freeze"
|
|
|
|
/>
|
2017-03-23 07:24:36 +08:00
|
|
|
</circle>
|
2016-07-16 04:45:54 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Cursor.propTypes = propTypes;
|
|
|
|
Cursor.defaultProps = defaultProps;
|