ImagePreview.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import React from 'react';
  2. import styles from './ImagePreview.less';
  3. import { Icon } from 'antd'
  4. import PropTypes from 'prop-types';
  5. import { util } from 'utils';
  6. const maxWidth = 500;
  7. class ImagePreview extends React.Component {
  8. constructor(props) {
  9. super(props);
  10. this.state = {
  11. showMagnifier: false,
  12. scale: 1,
  13. rotate: 0,
  14. left: 0,
  15. top: 0,
  16. leftRatio: 0,
  17. topRatio: 0,
  18. imgWidth: 0,
  19. imgHeight: 0,
  20. id: util.string.generateRandom(8)
  21. }
  22. }
  23. mouseEnter() {
  24. this.setState({ showMagnifier: true })
  25. }
  26. mouseLeave() {
  27. this.setState({ showMagnifier: false })
  28. }
  29. mouseMove(ev) {
  30. let oShadow = document.getElementById(`preview_shadow_${this.state.id}`);
  31. //鼠标相对于视口的位置
  32. let x = ev.clientX;
  33. let y = ev.clientY;
  34. //box相对于视口的位置
  35. let element = document.getElementById(`preview_box_${this.state.id}`);
  36. let boxTop = element.getBoundingClientRect().top;
  37. let boxLeft = element.getBoundingClientRect().left;
  38. //move相对位置
  39. let left = x - boxLeft - oShadow.offsetWidth / 2;
  40. let top = y - boxTop - oShadow.offsetHeight / 2;
  41. let maxLeft = element.offsetWidth - oShadow.offsetWidth;
  42. let maxTop = element.offsetHeight - oShadow.offsetHeight;
  43. if (left <= 0) {
  44. left = 0;
  45. } else if (left > maxLeft) {
  46. left = maxLeft;
  47. }
  48. if (top <= 0) {
  49. top = 0;
  50. } else if (top > maxTop) {
  51. top = maxTop;
  52. }
  53. this.setState({
  54. left: left,
  55. top: top,
  56. leftRatio: left / maxLeft,
  57. topRatio: top / maxTop
  58. });
  59. }
  60. onScaleChange(scale) {
  61. if (scale < 0) return;
  62. this.setState({ scale: scale });
  63. }
  64. onRotateChange(rotate) {
  65. this.setState({ rotate: rotate });
  66. }
  67. componentDidMount() {
  68. this.initImageSize();
  69. }
  70. initImageSize() {
  71. let image = document.getElementById(`preview_img_${this.state.id}`);
  72. if (image == null) {
  73. setTimeout(() => this.initImageSize(), 500);
  74. return;
  75. };
  76. if (image.naturalWidth > 0) {
  77. this.setState({
  78. imgWidth: image.naturalWidth,
  79. imgHeight: image.naturalHeight
  80. })
  81. } else {
  82. var img = new Image()
  83. img.src = image.src;
  84. img.onload = () => {
  85. this.setState({
  86. imgWidth: img.width,
  87. imgHeight: img.height
  88. });
  89. }
  90. }
  91. }
  92. render() {
  93. if (!this.props.url) return <span />;
  94. let imgStyle = {}, shadowStyle = {}, bigBoxStyle = {};
  95. let bigImgStyle = {
  96. width: this.state.imgWidth,
  97. height: this.state.imgHeight
  98. };
  99. if (this.state.imgWidth > 0) {
  100. let boxImgWidth = this.state.imgWidth > maxWidth ? maxWidth : this.state.imgWidth;
  101. imgStyle.width = boxImgWidth;
  102. imgStyle.height = this.state.imgHeight * boxImgWidth / this.state.imgWidth;
  103. }
  104. if (this.state.scale > 0) {
  105. imgStyle.transform = 'scale(' + this.state.scale + ',' + this.state.scale + ')';
  106. }
  107. if (this.state.showMagnifier) {
  108. shadowStyle = {
  109. display: 'block',
  110. top: this.state.top,
  111. left: this.state.left
  112. };
  113. bigBoxStyle = {
  114. display: 'block'
  115. };
  116. let bigBoxEle = document.getElementById(`preview_bigbox_${this.state.id}`);
  117. let bigImgEle = document.getElementById(`preview_bigimg_${this.state.id}`);
  118. bigImgStyle.top = (bigImgEle.offsetHeight - bigBoxEle.offsetHeight) * this.state.topRatio * (-1);
  119. bigImgStyle.left = (bigImgEle.offsetWidth - bigBoxEle.offsetWidth) * this.state.leftRatio * (-1);
  120. } else {
  121. shadowStyle = { display: 'none' };
  122. bigBoxStyle = { display: 'none' };
  123. }
  124. if (this.state.rotate > 0) {
  125. bigImgStyle.transform = 'rotate(' + this.state.rotate + 'deg)';
  126. if (imgStyle.transform) {
  127. imgStyle.transform += ' rotate(' + this.state.rotate + 'deg)';
  128. } else {
  129. imgStyle.transform = 'rotate(' + this.state.rotate + 'deg)';
  130. }
  131. }
  132. return (
  133. <div className={styles.preview}>
  134. <div id={`preview_box_${this.state.id}`} className={styles.box} onMouseEnter={() => this.mouseEnter()} onMouseLeave={() => this.mouseLeave()} onMouseMove={e => this.mouseMove(e)}>
  135. <img id={`preview_img_${this.state.id}`} src={this.props.url} style={imgStyle} />
  136. <div id={`preview_shadow_${this.state.id}`} className={styles.shadow} style={shadowStyle}></div>
  137. </div>
  138. <span className={styles.rotate} >
  139. <Icon type="plus-circle-o" style={{ fontWeight: '600', fontSize: '16px' }} onClick={() => this.onScaleChange(this.state.scale + 0.1)} />
  140. <Icon type="minus-circle-o" className={styles.minus} style={{ fontWeight: '600', fontSize: '16px' }} onClick={() => this.onScaleChange(this.state.scale - 0.1)} />
  141. <Icon type="reload" style={{ fontWeight: '600', fontSize: '16px' }} onClick={() => this.onRotateChange(this.state.rotate + 90)} />
  142. </span>
  143. {/*大盒子*/}
  144. <div id={`preview_bigbox_${this.state.id}`} className={styles.bigbox} style={bigBoxStyle}>
  145. <img id={`preview_bigimg_${this.state.id}`} src={this.props.url} style={bigImgStyle} />
  146. </div>
  147. </div>
  148. )
  149. }
  150. }
  151. ImagePreview.propTypes = {
  152. url: PropTypes.string,
  153. name: PropTypes.string
  154. };
  155. ImagePreview.defaultProps = {
  156. };
  157. export default ImagePreview