123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- import Drawer from './drawer.js';
- class ROIDrawer extends Drawer {
- constructor(props) {
- super(props);
- 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', this._onClick.bind(this));
- this.canvas.addEventListener('contextmenu', this._oncontextmenu.bind(this));
- this.canvas.addEventListener('mousemove', this._onmousemove.bind(this));
- }
- _onClick(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);
- }
- _oncontextmenu(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]);
- if (this.polygons.length < this.MAX_POLYGON) {
- this._resetPoints();
- } else {
- this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
- this._drawPolygons([]);
- }
- }
- }
- }
- _onmousemove(e) {
- let pos = getMousePos(this.canvas, e);
- //console.log('mousemove');
- if (e.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) {
- if (!polygons) {
- return;
- }
- let data = [];
- this.polygons = [];
- 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;
- this.canvas.removeEventListener('click', this._onClick);
- this.canvas.removeEventListener('contextmenu', this._oncontextmenu);
- this.canvas.removeEventListener('mousemove', this._onmousemove);
- }
- _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();
- }
- }
- class StandingDrawer extends Drawer {
- constructor(props) {
- super(props);
- this.currentState = 'end';
- this.points = [];
- this.onDrawROIFinishedCallback = null;
- }
- _init() {
- this.context.lineWidth = 2;
- this.context.font = 'bold 20px Arial';
- this.canvas.addEventListener('click', this._onClick.bind(this));
- this.canvas.addEventListener('contextmenu', this._oncontextmenu.bind(this));
- this.canvas.addEventListener('mousemove', this._onmousemove.bind(this));
- }
- _onClick(e) {
- let pos = getMousePos(this.canvas, e);
- switch (this.currentState) {
- case 'begin':
- this.points.push(pos);
- this.currentState = 'firstPoint';
- break;
- case 'firstPoint': // 防止初始点点两次
- break;
- case 'move':
- this.currentState = 'points';
- break;
- case 'points':
- if (((pos.x === this.points[this.points.length - 1].x) && (pos.y === this.points[this.points.length - 1].y))
- || this.points.length > 6) {
- return;
- }
- this.points.push(pos);
- let points = this.points.length > 4 ? this.points.slice(0, 4) : this.points;
- if (checkPolygon(points)) {
- this.points.pop();
- }
- if (this.points.length === 6) {
- this.currentState = 'end';
- this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
- }
- this._drawArea(this.points);
- break;
- case 'end':
- break;
- default:
- console.log('unknown state: ', this.currentState);
- break;
- }
- }
- _oncontextmenu(e) {
- e.preventDefault();
- }
- _onmousemove(e) {
- let pos = getMousePos(this.canvas, e);
- if (e.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._drawArea(this.points);
- this.points.pop();
- } else {
- }
- // if(this.currentState === 'begin') {
- // this._drawText('区域' + (this.polygons.length + 1), pos.x, pos.y)
- // }
- }
- }
- _drawArea(points) {
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
- let polygon = points.length > 4 ? points.slice(0, 4) : points;
- this._drawPolygon(polygon);
- let line = points.length > 4 ? points.slice(4) : [];
- this._drawLine(line);
- }
- _drawPolygon(points) {
- if (!points.length) {
- return;
- }
- this.context.strokeStyle = '#00ff00';
- 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);
- }
- this.points.length >= 4 && this.context.lineTo(points[0].x, points[0].y);
- this.context.stroke();
- this.context.closePath();
- }
- _drawLine(points) {
- if (points.length !== 2) {
- return;
- }
- this.context.strokeStyle = '#0000ff';
- this.context.beginPath();
- this.context.moveTo(points[0].x, points[0].y);
- this.context.lineTo(points[1].x, points[1].y);
- this.context.stroke();
- this.context.closePath();
- }
- getROIData() {
- if (this.currentState !== 'end') { //非完成状态
- return null;
- }
- let points = [];
- this.points.map((point, k) => {
- points.push(this._to8191Coordinate(point, this.canvas));
- });
- return points;
- }
- setROI(points) {
- if (!points) {
- return;
- }
- let data = [];
- points.map((point, k) => {
- let result = this._toRealCoordinate(point.x, point.y);
- data[k] = { x: result[0], y: result[1] };
- });
- this.points = [...data];
- this._drawArea(data);
- this.currentState = 'end';
- }
- redrawROI() {
- this._drawArea(this.points);
- }
- reset() {
- this.currentState = 'begin';
- this.points.length = 0;
- this._drawArea(this.points);
- }
- setROIFinishedCallback(callback) {
- this.onDrawROIFinishedCallback = callback;
- }
- terminate() {
- this.clearCanvas();
- this.canvas.width = 0;
- this.canvas.height = 0;
- this.currentState = 'end';
- this.points.length = 0;
- this.canvas.removeEventListener('click', this._onClick);
- this.canvas.removeEventListener('contextmenu', this._oncontextmenu);
- this.canvas.removeEventListener('mousemove', this._onmousemove);
- }
- }
- class SpeedLine extends Drawer {
- constructor(canvas) {
- super(canvas);
- this.currentState = 'end';
- this.MAXLINE = 2;
- this.points = [];
- this.onDrawROIFinishedCallback = null;
- }
- _init() {
- this.canvas.addEventListener('click', this._onClick.bind(this));
- this.canvas.addEventListener('contextmenu', this._oncontextmenu.bind(this));
- this.canvas.addEventListener('mousemove', this._onmousemove.bind(this));
- }
- _onClick(e) {
- if (this.points.length === this.MAXLINE * 2) {
- return;
- }
- 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 (this.points.length === this.MAXLINE * 2) {
- if (this._checkLine(this.points)) {
- this.points.pop();
- } else {
- this.currentState = 'end';
- this._drawLines(this.points);
- this.onDrawROIFinishedCallback && this.onDrawROIFinishedCallback();
- }
- }
- break;
- case 'end':
- break;
- default:
- console.log('unknown state: ', this.currentState);
- break;
- }
- }
- _onmousemove(e) {
- let pos = getMousePos(this.canvas, e);
- if (e.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.currentState !== 'begin') {
- this.points.push(pos);
- this._drawLines(this.points);
- this.points.pop();
- }
- }
- }
- _oncontextmenu(e) {
- e.preventDefault();
- }
- /**
- *
- * @param points [] x1,y1,x2,y2...
- * @private
- */
- _checkLine(points) {
- for (let i = 0; i < points.length - 3; i = i + 2) {
- for (let j = i + 2; j < points.length - 1; j = j + 2) {
- 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;
- }
- _drawLines(points) {
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
- if (!points.length) {
- return;
- }
- const end = this.currentState === 'end';
- this.context.strokeStyle = end ? '#00ff00' : "#ffff00";
- this.context.beginPath();
- for (let i = 0; i < points.length - 1; i = i + 2) {
- this.context.moveTo(points[i].x, points[i].y);
- this.context.lineTo(points[i + 1].x, points[i + 1].y);
- }
- this.context.stroke();
- this.context.closePath();
- }
- getROIData() {
- if (this.currentState !== 'end') { //非完成状态
- return null;
- }
- let data = this.points;
- data.map((point, k) => {
- data[k] = this._to8191Coordinate(point, this.canvas);
- });
- return data;
- }
- setROI(data) {
- data.map((point, k) => {
- let result = this._toRealCoordinate(point.x, point.y);
- data[k] = { x: result[0], y: result[1] };
- });
- this.currentState = 'end';
- this.points = data;
- this._drawLines(this.points);
- }
- redrawROI() {
- this._drawLines(this.points);
- }
- reset() {
- this.currentState = 'begin';
- this.points.length = 0;
- console.log(this.points)
- this._drawLines(this.points);
- }
- setROIFinishedCallback(callback) {
- this.onDrawROIFinishedCallback = callback;
- }
- setLineNum(num) {
- this.MAXLINE = num;
- }
- terminate() {
- this.clearCanvas();
- this.canvas.width = 0;
- this.canvas.height = 0;
- this.currentState = 'end';
- this.points.length = 0;
- this.canvas.removeEventListener('click', this._onClick);
- this.canvas.removeEventListener('contextmenu', this._oncontextmenu);
- this.canvas.removeEventListener('mousemove', this._onmousemove);
- }
- }
- class BlankROIDrawer extends Drawer {
- constructor(canvas) {
- super(canvas);
- }
- getROIData() {
- }
- setROI() {
- }
- redrawROI() {
- }
- reset() {
- }
- terminate() {
- }
- }
- 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 { ROIDrawer, StandingDrawer, SpeedLine, BlankROIDrawer };
|