React+canvas
React.js
自适应:在less里面设置rem会变形,所以用fontSize在页面设置canvas的尺寸。
父类div:为position: relative,里面的canvas为position: absolute;比较好计算距离屏幕的距离。
标尺跟随鼠标移动:跟随鼠标移动的标尺为position: absolute;比较好计算距离屏幕的距离。
class SecondaryZone extends Component { state = { isBut: { isButEdit: true, isButReset: false, isButSave: false, }, scenemarList: [] } componentDidMount() { const { isBut } = this.state let { secondaryZone, isButEdit } = this.props isBut.isButEdit = isButEdit this.setState({ isBut, scenemarList: secondaryZone }, () => { this.setCanvas() }) } // 数值渲染到canvas上面 setCanvas = () => { const { scenemarList } = this.state const { fontSize } = this.props const c = document.getElementById("canvasBox"); const cxt = c.getContext("2d"); cxt.clearRect(0, 0, c.width, c.height); cxt.beginPath(); cxt.strokeStyle = "#000"; cxt.lineWidth = 0.2 * fontSize; cxt.fillStyle = "#000"; if (scenemarList) { cxt.beginPath(); cxt.strokeStyle = "#FEF448"; cxt.setLineDash([4, 4]); for (var k in scenemarList) { if (k === 0) { // cxt.moveTo(scenemarList[k][0] / 16 * fontSize, scenemarList[k][1] / 16 * fontSize); cxt.moveTo(scenemarList[k][0], scenemarList[k][1]); } else { // cxt.lineTo(scenemarList[k][0] / 16 * fontSize, scenemarList[k][1] / 16 * fontSize); cxt.lineTo(scenemarList[k][0], scenemarList[k][1]); } } cxt.closePath(); cxt.stroke(); } } // canvas 点击事件,添加点位 changeCanvas = (event) => { const { isBut } = this.state if (isBut.isButSave) { const pointTop = document.getElementsByClassName("videoBox")[0].offsetTop const pointLeft = document.getElementsByClassName("videoBox")[0].offsetLeft const addModalTop = document.getElementsByClassName("secondary")[0].offsetTop const addModalLeft = document.getElementsByClassName("secondary")[0].offsetLeft const top = event.pageY - pointTop - addModalTop const left = event.pageX - pointLeft - addModalLeft // console.log("top:", top, top / 16, " left:", left, left / 16) let { scenemarList } = this.state const scenemarArr = Object.keys(scenemarList) scenemarList[scenemarArr.length] = [left, top] this.setState({ scenemarList }, this.setCanvas) } } //场景设置,鼠标移动 canvasMouseMove = (event) => { if (document.getElementsByClassName("canvasX")[0]) { const pointTop = document.getElementsByClassName("videoBox")[0].offsetTop const pointLeft = document.getElementsByClassName("videoBox")[0].offsetLeft const addModalTop = document.getElementsByClassName("secondary")[0].offsetTop const addModalLeft = document.getElementsByClassName("secondary")[0].offsetLeft const top = event.pageY - pointTop - addModalTop const left = event.pageX - pointLeft - addModalLeft if (event.pageY - top >= 0) { document.getElementsByClassName("canvasX")[0].style.top = top + "px"; } if (event.pageX - left >= 0) { document.getElementsByClassName("canvasY")[0].style.left = left + "px"; } } } render() { const { fontSize, saveModle, cancelModle } = this.props const { isBut, scenemarList } = this.state return <div className="secondaryZone"> <div className="videoBac"> <div className="videoBox"> <video id="video" width={fontSize * 75.2} height={fontSize * 41.25}></video> <canvas id="canvasBox" width={fontSize * 75.2} height={fontSize * 41.25} onClick={this.changeCanvas} onMouseMove={this.canvasMouseMove}></canvas> {isBut.isButSave ? <div className="canvasX"></div> : ""} {isBut.isButSave ? <div className="canvasY"></div> : ""} </div> </div> </div> } } export default SecondaryZone
Less
.secondaryZone { min-height: 52rem; .videoBac { 83.13rem; height: 50rem; background: url(../img/videoBig.svg) no-repeat; background-size: 100%; .videoBox { 75.2rem; height: 41.25rem; position: relative; z-index: 888; right: 0; left: 0; top: 4.12rem; margin: auto; > video { position: absolute; top: 0; left: 0; transform: rotateY(180deg); 100%; height: 100%; } #canvasBox { position: absolute; top: 0; left: 0; 100%; height: 100%; z-index: 100; } .canvasX { border-top: 1px dashed pink; 100%; position: absolute; top: 0; left: 0; } .canvasY { border-left: 1px dashed pink; 1px; height: 100%; position: absolute; top: 0; left: 0; } } } }