最近項目中有一個需求, 在提供的圖片上畫出圖形區(qū)域惨远,并且圖形可以編輯改變。
問題點:
1孵奶、圖形為多邊形疲酌,畫圖需要canvas來實現(xiàn);
2拒课、圖片存在縮放的問題徐勃,需要讓canvas match渲染出的圖片事示;
React Canvas
先放結論:react canvas 繪制2d 畫布有bug,繪制指定兩點坐標的圖形錯誤僻肖。
后來發(fā)現(xiàn)肖爵,原來從18年開始,react 已不再維護canvas 相關api臀脏。
- 原生Canvas繪圖
<canvas id="canvas"></canvas>
....
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100, 100);
ctx.stroke();
效果如下
- React Canvas 繪圖
import React from "react";
export default class CanvasTest extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
}
componentDidMount() {
const { current } = this.ref;
if (!current) return;
const ctx = current.getContext("2d");
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100, 100);
ctx.stroke();
}
render() {
return (
<canvas
ref={this.ref}
style={{ width: "300px", height: "300px", border: "1px solid #000" }}
/>
);
}
}
效果如下
兩個點分別為(0,0), (100,100)劝堪。繪制出的線的斜率不一致。
- 解決辦法:React Konva
React Konva 是Konva的基于React 的實現(xiàn)揉稚。所有相關的API 可以查閱Konva中的文檔秒啦。
Canvas match 圖片
將canvas 以絕對定位的方式覆蓋在圖片上。以圖片縮放比例的方式來動態(tài)計算canvas 大小搀玖。
// 需要在圖片渲染后再調用calcViewPosition函數(shù)余境,所以需要根據(jù)實際的效果添加setTimeout;
calcViewPosition = () => {
if (!this.props.imgSize) {
return;
}
const parent = this.containerRef.current;
if (!parent) {
return;
}
const parentRect = parent.getBoundingClientRect();
const parentWidth = parentRect.width;
const parentHeight = parentRect.height;
const imageWidth = this.props.imgSize[0];
const imageHeight = this.props.imgSize[1];
const ratioX = imageWidth / parentWidth;
const ratioY = imageHeight / parentHeight;
let ratio = 0;
let offset = { left: 0, top: 0 };
if (ratioX < ratioY) {
ratio = this.props.objectFitContain ? ratioY : ratioX;
} else {
ratio = this.props.objectFitContain ? ratioX : ratioY;
}
offset.left = (parentWidth - imageWidth / ratio) / 2;
offset.top = (parentHeight - imageHeight / ratio) / 2;
this.setState({
offset,
ratio
});
}
...
<div className={styles.container} ref={this.containerRef}>
{imgSource && (
<img src={imgSource} style={{ objectFit: imgObjectFit }} className={styles.img} draggable={false} />
)}
<Stage
width={size.width / scale}
height={size.height / scale}
className={stageRectClass}
style={style}
onMouseUp={this.mouseUpEventHandler}
onMouseMove={this.mouseMoveEventHandler}
>
<Layer>
<Line points={pointers} stroke={lineColor} closed={true} strokeWidth={rectLineWidth} />
<Line
points={linePointers}
stroke={distanceLineColor}
closed={true}
strokeWidth={distanceLineWidth}
/>
</Layer>
</Stage>
</div>
// Less
.container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.stage {
position: absolute;
z-index: 10;
top: 0;
left: 0;
}
.img {
width: 100%;
height: 100%;
}
.stageLine {
.stage();
z-index: 20;
}
效果如下