img-marker
Version:
一个基于 canvas 的简单轻量级的图片标注库,支持多种图形标注 🚀🚀🚀
15 lines (14 loc) • 13.6 kB
JavaScript
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var t=function(e,i){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i])},t(e,i)};var e=function(){return e=Object.assign||function(t){for(var e,i=1,s=arguments.length;i<s;i++)for(var a in e=arguments[i])Object.prototype.hasOwnProperty.call(e,a)&&(t[a]=e[a]);return t},e.apply(this,arguments)};function i(t,e,i){if(i||2===arguments.length)for(var s,a=0,o=e.length;a<o;a++)!s&&a in e||(s||(s=Array.prototype.slice.call(e,0,a)),s[a]=e[a]);return t.concat(s||e)}var s,a,o,n=new(function(){function t(){this.eventTree=new Map}return t.prototype.on=function(t,e){var s,a=null!==(s=this.eventTree.get(t))&&void 0!==s?s:[];this.eventTree.set(t,i(i([],a,!0),[e],!1))},t.prototype.emit=function(t){for(var e,i=[],s=1;s<arguments.length;s++)i[s-1]=arguments[s];for(var a=0,o=null!==(e=this.eventTree.get(t))&&void 0!==e?e:[];a<o.length;a++){o[a].apply(null,i)}},t.prototype.off=function(t,e){var i,s=null!==(i=this.eventTree.get(t))&&void 0!==i?i:[],a=s.findIndex((function(t){return t===e}));s.splice(a,1),this.eventTree.set(t,s)},t}());exports.ShapeType=void 0,(s=exports.ShapeType||(exports.ShapeType={}))[s.rect=1]="rect",exports.MarkMode=void 0,(a=exports.MarkMode||(exports.MarkMode={}))[a.edit=0]="edit",a[a.rect=1]="rect",exports.EventType=void 0,(o=exports.EventType||(exports.EventType={})).Add="add",o.Select="select",o.Load="load",o.Update="update";var r=function(){var t;return null===(t=window.navigator)||void 0===t?void 0:t.userAgent.includes("Mobile")},h=function(e){function i(t){var i=e.call(this,t)||this;return i.type=exports.ShapeType.rect,i.type=exports.ShapeType.rect,i}return function(e,i){if("function"!=typeof i&&null!==i)throw new TypeError("Class extends value "+String(i)+" is not a constructor or null");function s(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(s.prototype=i.prototype,new s)}(i,e),Object.defineProperty(i.prototype,"ctrlsData",{get:function(){var t=this.coor,e=t[0],i=e[0],s=e[1],a=t[1],o=a[0],n=a[1];return[[i,s],[i+(o-i)/2,s],[o,s],[o,s+(n-s)/2],[o,n],[i+(o-i)/2,n],[i,n],[i,s+(n-s)/2]]},enumerable:!1,configurable:!0}),i.MIN_WIDTH=10,i.MIN_HEIGHT=10,i}((function(t){this.coor=[],this.strokeStyle="#FFE729",this.fillStyle="rgba(255,231,41, 0.2)",this.lineWidth=4,this.type=exports.ShapeType.rect,this.active=!1,this.creating=!1,this.dragging=!1,this.uuid=function(){if("object"==typeof crypto&&"function"==typeof crypto.randomUUID)return crypto.randomUUID();var t=(new Date).getTime();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){var i=16*Math.random();return i=(t+i)%16|0,t=Math.floor(t/16),("x"===e?i:3&i|8).toString(16)}))}(),Object.assign(this,t)})),c=function(){function t(t,e){this.CANVAS_WIDTH=0,this.CANVAS_HEIGHT=0,this.IMAGE_ORIGIN_WIDTH=0,this.IMAGE_ORIGIN_HEIGHT=0,this.IMAGE_WIDTH=0,this.IMAGE_HEIGHT=0,this.strokeStyle="#FFE729",this.fillStyle="rgba(255,231,41, 0.2)",this.lineWidth=4,this.activeStrokeStyle="#FFE729",this.activeFillStyle="rgba(255,231,41, 0.2)",this.ctrlStrokeStyle="#505E72",this.ctrlFillStyle="#fff",this.ctrlRadius=4,this.dataset=[],this.image=new Image,this.currentMode=exports.MarkMode.edit,this.ctrlIndex=-1,this.currentMousePoint=[0,0],this.handleLoad=this.handleLoad.bind(this),this.handleMouseDown=this.handleMouseDown.bind(this),this.handelMouseMove=function(t,e){void 0===e&&(e=200);var i=Date.now();return function(){for(var s=[],a=0;a<arguments.length;a++)s[a]=arguments[a];if(Date.now()-i>=e)return i=Date.now(),t.apply(void 0,s)}}(this.handelMouseMove.bind(this),16.7),this.handelMouseUp=this.handelMouseUp.bind(this),this.handelKeyup=this.handelKeyup.bind(this);var i="string"==typeof t?document.querySelector(t):t;i instanceof HTMLCanvasElement?(this.canvas=i,this.initSetting(),this.initEvents(),e&&this.setImage(e)):console.warn("HTMLCanvasElement is required!")}return Object.defineProperty(t.prototype,"activeShape",{get:function(){var t;return null!==(t=this.dataset.find((function(t){return t.active})))&&void 0!==t?t:null},enumerable:!1,configurable:!0}),t.prototype.initSetting=function(){this.ctx=this.ctx||this.canvas.getContext("2d",{alpha:!0}),this.CANVAS_WIDTH=this.canvas.clientWidth,this.CANVAS_HEIGHT=this.canvas.clientHeight,this.canvas.width=1*this.CANVAS_WIDTH,this.canvas.height=1*this.CANVAS_HEIGHT,this.canvas.style.width=this.CANVAS_WIDTH+"px",this.canvas.style.height=this.CANVAS_HEIGHT+"px",this.ctx.scale(1,1)},t.prototype.initEvents=function(){this.image.addEventListener("load",this.handleLoad),this.canvas.addEventListener("mousedown",this.handleMouseDown),this.canvas.addEventListener("mousemove",this.handelMouseMove),this.canvas.addEventListener("mouseup",this.handelMouseUp),document.body.addEventListener("keyup",this.handelKeyup)},t.prototype.destroy=function(){this.image.removeEventListener("load",this.handleLoad),this.canvas.removeEventListener("mousedown",this.handleMouseDown),this.canvas.removeEventListener("mousemove",this.handelMouseMove),this.canvas.removeEventListener("mouseup",this.handelMouseUp),document.body.removeEventListener("keyup",this.handelKeyup)},t.prototype.handleLoad=function(){this.IMAGE_ORIGIN_WIDTH=this.IMAGE_WIDTH=this.image.width,this.IMAGE_ORIGIN_HEIGHT=this.IMAGE_HEIGHT=this.image.height,this.fitZoom(),this.update()},t.prototype.handleMouseDown=function(t){var e,i,s,a=this;t.stopPropagation();var o=this.mergeEvent(t),c=o.mouseX,p=o.mouseY,u=o.mouseCX,d=o.mouseCY,l=r()&&2===t.touches.length?[u,d]:[c,p];if(!r()&&1===t.buttons||r()&&1===t.touches.length){this.currentMousePoint=l;var v=null!==(i=null===(e=this.activeShape)||void 0===e?void 0:e.ctrlsData)&&void 0!==i?i:[];if(this.ctrlIndex=v.findIndex((function(t){return a.isPointInCircle(l,t,a.ctrlRadius)})),this.ctrlIndex>-1)return void this.changeCursor("nwse-resize");if(this.currentMode>exports.MarkMode.edit){var f=void 0,y=[c,p];this.currentMode,exports.MarkMode.rect,(f=new h({coor:[y,y]})).creating=!0,this.dataset.forEach((function(t){t.active=!1})),f.active=!0,this.dataset.push(f)}else{var I=this.isHitOnShape(l),S=I.isOnShape,x=I.shape,g=I.index;S?((null===(s=this.activeShape)||void 0===s?void 0:s.uuid)!==x.uuid&&n.emit(exports.EventType.Select,x),this.dataset.map((function(t){return t.active=t.uuid===x.uuid})),x.dragging=!0,this.dataset.splice(g,1),this.dataset.push(x),this.changeCursor("move")):this.activeShape&&(this.activeShape.active=!1)}this.update()}},t.prototype.handelMouseMove=function(t){var e;t.stopPropagation();var i=this.mergeEvent(t),s=i.mouseX,a=i.mouseY,o=i.mouseCX,n=i.mouseCY,c=r()&&2===t.touches.length?[o,n]:[s,a],p=this.isHitOnShape(c),u=p.isOnShape,d=p.shape;if(this.ctrlIndex>-1?this.changeCursor("nwse-resize"):this.currentMode>exports.MarkMode.edit?this.changeCursor("copy"):u?this.changeCursor(d.active?"move":"pointer"):this.changeCursor("default"),(!r()&&1===t.buttons||r()&&1===t.touches.length)&&(null===(e=this.activeShape)||void 0===e?void 0:e.type)){if(this.ctrlIndex>-1){if(this.activeShape.type===exports.ShapeType.rect){var l=this.activeShape.coor,v=l[0],f=v[0],y=v[1],I=l[1],S=I[0],x=I[1],g=[];switch(this.ctrlIndex){case 0:g=[[s,a],[S,x]];break;case 1:g=[[f,a],[S,x]];break;case 2:g=[[f,a],[s,x]];break;case 3:g=[[f,y],[s,x]];break;case 4:g=[[f,y],[s,a]];break;case 5:g=[[f,y],[S,a]];break;case 6:g=[[s,y],[S,a]];break;case 7:g=[[s,y],[S,x]]}var M=g[0],H=M[0],T=M[1],E=g[1],m=E[0],A=E[1];m-H>=h.MIN_WIDTH&&A-T>=h.MIN_HEIGHT&&(this.activeShape.coor=[[H,T],[m,A]])}}else if(this.activeShape.dragging){g=[];for(var _=!0,C=0;C<this.activeShape.coor.length;C++){var G=this.activeShape.coor[C],w=G[0],b=G[1],D=w+s-this.currentMousePoint[0],N=b+a-this.currentMousePoint[1];(D<0||D>this.CANVAS_WIDTH||N<0||N>this.CANVAS_HEIGHT)&&(_=!1),g.push([D,N])}_&&(this.activeShape.coor=g)}else this.activeShape.creating&&(this.changeCursor("nwse-resize"),this.activeShape.type===exports.ShapeType.rect&&this.activeShape.coor.splice(1,1,[s,a]));this.currentMousePoint=c,this.update()}},t.prototype.handelMouseUp=function(t){var e;if(t.stopPropagation(),this.ctrlIndex=-1,(null===(e=this.activeShape)||void 0===e?void 0:e.type)&&(this.activeShape.dragging=!1,this.activeShape.creating)){if(this.activeShape.type===exports.ShapeType.rect){var i=this.activeShape.coor,s=i[0],a=s[0],o=s[1],r=i[1],c=r[0],p=r[1];Math.abs(a-c)<h.MIN_WIDTH||Math.abs(o-p)<h.MIN_HEIGHT?this.dataset.pop():(this.activeShape.coor=[[Math.min(a,c),Math.min(o,p)],[Math.max(a,c),Math.max(o,p)]],this.activeShape.creating=!1)}n.emit(exports.EventType.Add,this.activeShape),this.update()}},t.prototype.handelKeyup=function(t){var e;t.stopPropagation(),(null===(e=this.activeShape)||void 0===e?void 0:e.type)&&("Backspace"!==t.key&&"Escape"!==t.key||this.deleteByUuid(this.activeShape.uuid))},t.prototype.fitZoom=function(){var t=this.CANVAS_WIDTH/this.CANVAS_HEIGHT,e=this.IMAGE_ORIGIN_WIDTH/this.IMAGE_ORIGIN_HEIGHT;t>e?(this.IMAGE_HEIGHT=this.CANVAS_HEIGHT,this.IMAGE_WIDTH=this.CANVAS_HEIGHT*e):(this.IMAGE_WIDTH=this.CANVAS_WIDTH,this.IMAGE_HEIGHT=this.CANVAS_WIDTH/e)},t.prototype.setData=function(t){this.dataset=t.map((function(t){return t.type,exports.ShapeType.rect,new h(t)})),this.update()},t.prototype.setMode=function(t){this.currentMode=t},t.prototype.on=function(t,e){n.on(t,e)},t.prototype.deleteByUuid=function(t){var e=this.dataset.findIndex((function(e){return e.uuid===t}));e>-1&&(this.dataset.splice(e,1),this.update())},t.prototype.update=function(){this.ctx.save(),this.ctx.clearRect(0,0,this.CANVAS_WIDTH,this.CANVAS_HEIGHT),this.drawShapes(),this.activeShape&&[exports.ShapeType.rect].includes(this.activeShape.type)&&this.drawCtrlList(this.activeShape),this.ctx.restore(),n.emit(exports.EventType.Update,this.dataset)},t.prototype.drawShapes=function(){for(var t=0;t<this.dataset.length;t++){var e=this.dataset[t];if(e.type===exports.ShapeType.rect)this.drawRect(e)}},t.prototype.drawImg=function(){var t=(this.CANVAS_WIDTH-this.IMAGE_WIDTH)/2,e=(this.CANVAS_HEIGHT-this.IMAGE_HEIGHT)/2;this.ctx.drawImage(this.image,t,e,this.IMAGE_WIDTH,this.IMAGE_HEIGHT)},t.prototype.drawRect=function(t){if(2===t.coor.length){var e=t.strokeStyle,i=t.fillStyle,s=t.active,a=t.creating,o=t.coor,n=t.lineWidth,r=o[0],h=r[0],c=r[1],p=o[1],u=p[0],d=p[1];this.ctx.save(),this.ctx.lineWidth=n||this.lineWidth,this.ctx.fillStyle=i||this.fillStyle,this.ctx.strokeStyle=s||a?this.activeStrokeStyle:e||this.strokeStyle;var l=u-h,v=d-c;this.ctx.fillRect(h,c,l,v),this.ctx.strokeRect(h,c,l,v),this.ctx.restore()}},t.prototype.drawCtrlList=function(t){var e=this;t.ctrlsData.forEach((function(t,i){e.drawCtrl(t)}))},t.prototype.drawCtrl=function(t){var e=t[0],i=t[1];this.ctx.save(),this.ctx.beginPath(),this.ctx.fillStyle=this.ctrlFillStyle,this.ctx.strokeStyle=this.ctrlStrokeStyle,this.ctx.arc(e,i,this.ctrlRadius,0,2*Math.PI,!0),this.ctx.fill(),this.ctx.arc(e,i,this.ctrlRadius,0,2*Math.PI,!0),this.ctx.stroke(),this.ctx.restore()},t.prototype.setImage=function(t){this.image.src=t,this.image.crossOrigin="anonymous",this.canvas.style.backgroundImage='url("'.concat(t,'")'),this.canvas.style.backgroundSize="contain",this.canvas.style.backgroundRepeat="no-repeat",this.canvas.style.backgroundPosition="center center",this.image.onload=function(){n.emit(exports.EventType.Load)}},t.prototype.exportImg=function(t,e){return void 0===t&&(t="image/png"),void 0===e&&(e=1),this.activeShape&&(this.activeShape.active=!1),this.ctx.save(),this.ctx.clearRect(0,0,this.CANVAS_WIDTH,this.CANVAS_HEIGHT),this.ctx.fillStyle="#fff",this.ctx.fillRect(0,0,this.CANVAS_WIDTH,this.CANVAS_HEIGHT),this.drawImg(),this.drawShapes(),this.ctx.restore(),this.canvas.toDataURL(t,e)},t.prototype.mergeEvent=function(t){var i=0,s=0,a=0,o=0;if(r()){var n=t.touches[0],h=n.clientX,c=n.clientY,p=t.target.getBoundingClientRect(),u=p.left,d=p.top;if(i=Math.round(h-u),s=Math.round(c-d),2===t.touches.length){var l=t.touches[1]||{},v=l.clientX,f=void 0===v?0:v,y=l.clientY,I=void 0===y?0:y;a=Math.round(Math.abs((f-h)/2+h)-u),o=Math.round(Math.abs((I-c)/2+c)-d)}}else i=t.offsetX,s=t.offsetY;return e(e({},t),{mouseX:i,mouseY:s,mouseCX:a,mouseCY:o})},t.prototype.isPointInCircle=function(t,e,i){var s=t[0],a=t[1],o=e[0],n=e[1];return Math.sqrt(Math.pow(o-s,2)+Math.pow(n-a,2))<=i},t.prototype.isPointInRect=function(t,e){var i=t[0],s=t[1],a=e[0],o=a[0],n=a[1],r=e[1],h=r[0],c=r[1];return o<=i&&i<=h&&n<=s&&s<=c},t.prototype.isHitOnShape=function(t){for(var e=this.dataset.length-1;e>=0;e--){var i=this.dataset[e];if(i.type===exports.ShapeType.rect&&this.isPointInRect(t,i.coor))return{isOnShape:!0,index:e,shape:i}}return{isOnShape:!1,index:-1,shape:null}},t.prototype.changeCursor=function(t){this.canvas.style.cursor=t},t}();exports.default=c;