UNPKG

react-svg-camera

Version:

React component to zoom and scroll an svg element

83 lines (73 loc) 2.24 kB
var React = require('react'); module.exports = React.createClass({ displayName: 'SvgCamera', propTypes: { camera: React.PropTypes.shape({ x: React.PropTypes.number.isRequired, y: React.PropTypes.number.isRequired, zoom: zoomIsNumberGreaterThanZero }).isRequired }, componentWillMount: function componentWillMount() { if (!this.knowsSize()) { // trigger a render in addition to the initial render so svg's size will // be known this.forceUpdate(); } }, render: function render() { var viewbox = this.generateViewBox(this.props); return ( <svg {...this.props} viewBox={viewbox} ref={this.cacheSize}> {this.props.children} </svg> ); }, cacheSize: function cacheSize(svgElement) { if (svgElement) { var rect = svgElement.getBoundingClientRect(); this.setSize({ width: rect.width, height: rect.height }); } else { this.setSize(null); } }, knowsSize: function knowsSize() { return !!this._size; }, getSize: function getSize() { return this._size; }, setSize: function setSize(size) { this._size = size; }, generateViewBox: function generateViewBox(props) { if (!this.knowsSize()) { return null; } var size = this.getSize(); var width = size.width; var height = size.height; var camera = props.camera; // camera x/y is its center so translate by half size to get its // top/left point because that's what viewbox uses var cameraX = camera.x - width / 2; var cameraY = camera.y - height / 2; var viewBoxWidth = width / camera.zoom; var viewBoxHeight = height / camera.zoom; var viewBoxX = cameraX - ((viewBoxWidth - width) / 2); var viewBoxY = cameraY - ((viewBoxHeight - height) / 2); return viewBoxX + ' ' + viewBoxY + ' ' + viewBoxWidth + ' ' + viewBoxHeight; } }); function zoomIsNumberGreaterThanZero(props, propName, componentName) { var value = props[propName]; if (typeof value != 'number' || value <= 0) { return new Error( 'Invalid prop `camera.zoom` supplied to `' + componentName + '`, expected `number greater than 0` but was `' + value + '`' ); } }