123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- import Drawer from './drawer.js';
- class ROIDrawer extends Drawer {
- constructor(canvas) {
- super(canvas);
- this.currentState = 'end';
- this.points = [];
- this.polygons = [];
- this.MAX_POLYGON = 1;
- this.onDrawROIFinishedCallback = null;
- }
- _init() {
- this.context.lineWidth = 2;
- this.context.font = 'bold 20px Arial';
- this.canvas.addEventListener('click', (e) => {
- switch (this.currentState) {
- case 'begin':
- this.points.push(getMousePos(this.canvas, e));
- this.currentState = 'firstPoint';
- break;
- case 'firstPoint': // 防止初始点点两次
- break;
- case 'move':
- this.currentState = 'points';
- break;
- case 'points':
- let currentPoint = getMousePos(this.canvas, e);
- if ((currentPoint.x === this.points[this.points.length - 1].x) && (currentPoint.y === this.points[this.points.length - 1].y)) {
- return;
- }
- this.points.push(currentPoint);
- if (checkPolygon(this.points)) {
- this.points.pop();
- }
- //console.log(this.points);
- break;
- case 'end':
- //console.log(this.points)
- break;
- default:
- console.log('unknown state: ', this.currentState);
- break;
- }
- // this._drawPolygons(this.points, true);
- });
- this.canvas.addEventListener('contextmenu', (e) => {
- e.preventDefault();
- if(this.currentState === 'end') { //防止点击右键启动绘制
- return ;
- }
- if (this.points.length <= 2) {
- this._resetPoints();
- } else {
- if ((this.points[0].x !== this.points[this.points.length - 1].x) || (this.points[0].y !== this.points[this.points.length - 1].y)) {
- this.points.push(this.points[0]);
- }
- if (checkPolygon(this.points)) {
- this.points.pop();
- } else {
- this.currentState = 'end';
- this.polygons.push([...this.points]);
- this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
- if(this.polygons.length < this.MAX_POLYGON) {
- this._resetPoints();
- } else {
- this._drawPolygons([]);
- }
- }
- }
- });
- this.canvas.addEventListener('mousemove', (event) => {
- let pos = getMousePos(this.canvas, event);
- //console.log('mousemove');
- if (event.button === 0) {
- if (this.currentState === 'firstPoint') {
- this.currentState = 'move';
- this.points.push(pos);
- } else if (this.currentState === 'move') {
- this.points.pop();
- this.points.push(pos);
- }
- if (this.currentState !== 'end') {
- this.points.push(pos);
- this._drawPolygons(this.points);
- this.points.pop();
- } else {
- //this._drawPolygons(this.points);
- }
- if(this.currentState === 'begin') {
- this._drawText('区域' + (this.polygons.length + 1), pos.x, pos.y)
- }
- }
- });
- }
- getROIData() {
- if(this.currentState !== 'end') { //非完成状态
- return null;
- }
- let polygons = [];
- this.polygons.map((points, k) =>{
- let data = points.slice(0, points.length - 1);
- data.map((point, k) => {
- data[k] = this._to8191Coordinate(point, this.canvas);
- });
- polygons.push([...data]);
- });
- return polygons;
- }
- setROI(polygons) {
- let data = [];
- polygons.map((points, k) => {
- points.map((point, k) => {
- let result = this._toRealCoordinate(point.x, point.y);
- data[k] = {x: result[0], y: result[1]};
- });
- if(data.length) {
- data[data.length] = data[0];
- }
- this.polygons.push([...data]);
- data = [];
- });
- this.currentState = 'end';
- this.points = [];
- this._drawPolygons(this.points);
- }
- redrawROI() {
- this._drawPolygons(this.points);
- }
- reset() {
- this.currentState = 'begin';
- this.polygons = [];
- this.points.length = 0;
- this._drawPolygons(this.points);
- }
- setROIFinishedCallback(callback) {
- this.onDrawROIFinishedCallback = callback;
- }
- setPolygonNum(num) {
- this.MAX_POLYGON = num;
- }
- terminate() {
- this.clearCanvas();
- this.canvas.width = 0;
- this.canvas.height = 0;
- this.currentState = 'end';
- this.points.length = 0;
- }
- _drawPolygons(points) {
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
- this.polygons.map((points, k)=> {
- this._drawPolygon(points);
- });
- this._drawPolygon(points);
- }
- _drawPolygon(points) {
- if (!points.length) {
- return;
- }
- const end = this.currentState === 'end';
- //console.log(points)
- this.context.strokeStyle = end ? '#0000ff' : "#ffff00";
- this.context.beginPath();
- this.context.moveTo(points[0].x, points[0].y);
- for (let i = 1; i < points.length; i++) {
- this.context.lineTo(points[i].x, points[i].y);
- }
- if (end) {
- // draw is done, fill polygon with a color
- this.context.fillStyle = "rgba(255, 0, 0, 0.2)";
- this.context.fill();
- } else {
- this.context.stroke();
- }
- this.context.closePath();
- this.polygons.map((points, k)=> {
- this._drawText('区域' + (k + 1), points[0].x - 20, points[0].y - 10);
- });
- }
- _resetPoints() {
- this.currentState = 'begin';
- this.points.length = 0;
- this._drawPolygons(this.points);
- }
- _drawText(text, x, y) {
- this.context.beginPath();
- this.context.fillStyle = "rgba(255, 255, 0, 1)";
- this.context.fillText(text, x, y);
- this.context.closePath();
- }
- }
- function getMousePos(canvas, event) {
- var rect = canvas.getBoundingClientRect();
- var x = event.clientX - rect.left * (canvas.width / rect.width);
- var y = event.clientY - rect.top * (canvas.height / rect.height);
- //console.log("x:"+x+",y:"+y);
- return {x: x, y: y};
- }
- function checkPolygon(points) {
- for (let i = 0, length = points.length - 1; i < length; i++) {
- for (let j = i + 1, len = points.length - 1; j < len; j++) {
- let result = segmentsIntr(points[i], points[i + 1], points[j], points[j + 1]);
- if (result) {
- console.log('intersect:');
- console.log(result)
- return result;
- }
- }
- }
- return false;
- }
- function segmentsIntr(a, b, c, d) {
- // 三角形abc 面积的2倍
- var area_abc = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
- // 三角形abd 面积的2倍
- var area_abd = (a.x - d.x) * (b.y - d.y) - (a.y - d.y) * (b.x - d.x);
- // 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,本例当作不相交处理);
- if (area_abc * area_abd >= 0) {
- return false;
- }
- // 三角形cda 面积的2倍
- var area_cda = (c.x - a.x) * (d.y - a.y) - (c.y - a.y) * (d.x - a.x);
- // 三角形cdb 面积的2倍
- // 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
- var area_cdb = area_cda + area_abc - area_abd;
- if (area_cda * area_cdb >= 0) {
- return false;
- }
- //计算交点坐标
- var t = area_cda / (area_abd - area_abc);
- var dx = t * (b.x - a.x),
- dy = t * (b.y - a.y);
- return {x: a.x + dx, y: a.y + dy};
- }
- export default ROIDrawer;
|