img-marker
Version:
一个基于 canvas 的简单轻量级的图片标注库,支持多种图形标注 🚀🚀🚀
14 lines (13 loc) • 13.7 kB
JavaScript
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).ImgMarker={})}(this,(function(t){"use strict";
/*! *****************************************************************************
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 e=function(t,i){return e=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])},e(t,i)};var i=function(){return i=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},i.apply(this,arguments)};function s(t,e,i){if(i||2===arguments.length)for(var s,a=0,n=e.length;a<n;a++)!s&&a in e||(s||(s=Array.prototype.slice.call(e,0,a)),s[a]=e[a]);return t.concat(s||e)}var a,n,o,r=function(){function t(){this.eventTree=new Map}return t.prototype.on=function(t,e){var i,a=null!==(i=this.eventTree.get(t))&&void 0!==i?i:[];this.eventTree.set(t,s(s([],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,n=null!==(e=this.eventTree.get(t))&&void 0!==e?e:[];a<n.length;a++){n[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}(),h=new r;t.ShapeType=void 0,(a=t.ShapeType||(t.ShapeType={}))[a.rect=1]="rect",t.MarkMode=void 0,(n=t.MarkMode||(t.MarkMode={}))[n.edit=0]="edit",n[n.rect=1]="rect",t.EventType=void 0,(o=t.EventType||(t.EventType={})).Add="add",o.Select="select",o.Load="load",o.Update="update";var c=function(){var t;return null===(t=window.navigator)||void 0===t?void 0:t.userAgent.includes("Mobile")},p=function(i){function s(e){var s=i.call(this,e)||this;return s.type=t.ShapeType.rect,s.type=t.ShapeType.rect,s}return function(t,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=t}e(t,i),t.prototype=null===i?Object.create(i):(s.prototype=i.prototype,new s)}(s,i),Object.defineProperty(s.prototype,"ctrlsData",{get:function(){var t=this.coor,e=t[0],i=e[0],s=e[1],a=t[1],n=a[0],o=a[1];return[[i,s],[i+(n-i)/2,s],[n,s],[n,s+(o-s)/2],[n,o],[i+(n-i)/2,o],[i,o],[i,s+(o-s)/2]]},enumerable:!1,configurable:!0}),s.MIN_WIDTH=10,s.MIN_HEIGHT=10,s}((function(e){this.coor=[],this.strokeStyle="#FFE729",this.fillStyle="rgba(255,231,41, 0.2)",this.lineWidth=4,this.type=t.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,e)})),u=function(){function e(e,i){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=t.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 s="string"==typeof e?document.querySelector(e):e;s instanceof HTMLCanvasElement?(this.canvas=s,this.initSetting(),this.initEvents(),i&&this.setImage(i)):console.warn("HTMLCanvasElement is required!")}return Object.defineProperty(e.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}),e.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)},e.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)},e.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)},e.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()},e.prototype.handleMouseDown=function(e){var i,s,a,n=this;e.stopPropagation();var o=this.mergeEvent(e),r=o.mouseX,u=o.mouseY,d=o.mouseCX,l=o.mouseCY,v=c()&&2===e.touches.length?[d,l]:[r,u];if(!c()&&1===e.buttons||c()&&1===e.touches.length){this.currentMousePoint=v;var f=null!==(s=null===(i=this.activeShape)||void 0===i?void 0:i.ctrlsData)&&void 0!==s?s:[];if(this.ctrlIndex=f.findIndex((function(t){return n.isPointInCircle(v,t,n.ctrlRadius)})),this.ctrlIndex>-1)return void this.changeCursor("nwse-resize");if(this.currentMode>t.MarkMode.edit){var y=void 0,I=[r,u];this.currentMode,t.MarkMode.rect,(y=new p({coor:[I,I]})).creating=!0,this.dataset.forEach((function(t){t.active=!1})),y.active=!0,this.dataset.push(y)}else{var S=this.isHitOnShape(v),g=S.isOnShape,M=S.shape,x=S.index;g?((null===(a=this.activeShape)||void 0===a?void 0:a.uuid)!==M.uuid&&h.emit(t.EventType.Select,M),this.dataset.map((function(t){return t.active=t.uuid===M.uuid})),M.dragging=!0,this.dataset.splice(x,1),this.dataset.push(M),this.changeCursor("move")):this.activeShape&&(this.activeShape.active=!1)}this.update()}},e.prototype.handelMouseMove=function(e){var i;e.stopPropagation();var s=this.mergeEvent(e),a=s.mouseX,n=s.mouseY,o=s.mouseCX,r=s.mouseCY,h=c()&&2===e.touches.length?[o,r]:[a,n],u=this.isHitOnShape(h),d=u.isOnShape,l=u.shape;if(this.ctrlIndex>-1?this.changeCursor("nwse-resize"):this.currentMode>t.MarkMode.edit?this.changeCursor("copy"):d?this.changeCursor(l.active?"move":"pointer"):this.changeCursor("default"),(!c()&&1===e.buttons||c()&&1===e.touches.length)&&(null===(i=this.activeShape)||void 0===i?void 0:i.type)){if(this.ctrlIndex>-1){if(this.activeShape.type===t.ShapeType.rect){var v=this.activeShape.coor,f=v[0],y=f[0],I=f[1],S=v[1],g=S[0],M=S[1],x=[];switch(this.ctrlIndex){case 0:x=[[a,n],[g,M]];break;case 1:x=[[y,n],[g,M]];break;case 2:x=[[y,n],[a,M]];break;case 3:x=[[y,I],[a,M]];break;case 4:x=[[y,I],[a,n]];break;case 5:x=[[y,I],[g,n]];break;case 6:x=[[a,I],[g,n]];break;case 7:x=[[a,I],[g,M]]}var T=x[0],H=T[0],m=T[1],E=x[1],A=E[0],_=E[1];A-H>=p.MIN_WIDTH&&_-m>=p.MIN_HEIGHT&&(this.activeShape.coor=[[H,m],[A,_]])}}else if(this.activeShape.dragging){x=[];for(var C=!0,G=0;G<this.activeShape.coor.length;G++){var b=this.activeShape.coor[G],w=b[0],D=b[1],k=w+a-this.currentMousePoint[0],N=D+n-this.currentMousePoint[1];(k<0||k>this.CANVAS_WIDTH||N<0||N>this.CANVAS_HEIGHT)&&(C=!1),x.push([k,N])}C&&(this.activeShape.coor=x)}else this.activeShape.creating&&(this.changeCursor("nwse-resize"),this.activeShape.type===t.ShapeType.rect&&this.activeShape.coor.splice(1,1,[a,n]));this.currentMousePoint=h,this.update()}},e.prototype.handelMouseUp=function(e){var i;if(e.stopPropagation(),this.ctrlIndex=-1,(null===(i=this.activeShape)||void 0===i?void 0:i.type)&&(this.activeShape.dragging=!1,this.activeShape.creating)){if(this.activeShape.type===t.ShapeType.rect){var s=this.activeShape.coor,a=s[0],n=a[0],o=a[1],r=s[1],c=r[0],u=r[1];Math.abs(n-c)<p.MIN_WIDTH||Math.abs(o-u)<p.MIN_HEIGHT?this.dataset.pop():(this.activeShape.coor=[[Math.min(n,c),Math.min(o,u)],[Math.max(n,c),Math.max(o,u)]],this.activeShape.creating=!1)}h.emit(t.EventType.Add,this.activeShape),this.update()}},e.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))},e.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)},e.prototype.setData=function(e){this.dataset=e.map((function(e){return e.type,t.ShapeType.rect,new p(e)})),this.update()},e.prototype.setMode=function(t){this.currentMode=t},e.prototype.on=function(t,e){h.on(t,e)},e.prototype.deleteByUuid=function(t){var e=this.dataset.findIndex((function(e){return e.uuid===t}));e>-1&&(this.dataset.splice(e,1),this.update())},e.prototype.update=function(){this.ctx.save(),this.ctx.clearRect(0,0,this.CANVAS_WIDTH,this.CANVAS_HEIGHT),this.drawShapes(),this.activeShape&&[t.ShapeType.rect].includes(this.activeShape.type)&&this.drawCtrlList(this.activeShape),this.ctx.restore(),h.emit(t.EventType.Update,this.dataset)},e.prototype.drawShapes=function(){for(var e=0;e<this.dataset.length;e++){var i=this.dataset[e];if(i.type===t.ShapeType.rect)this.drawRect(i)}},e.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)},e.prototype.drawRect=function(t){if(2===t.coor.length){var e=t.strokeStyle,i=t.fillStyle,s=t.active,a=t.creating,n=t.coor,o=t.lineWidth,r=n[0],h=r[0],c=r[1],p=n[1],u=p[0],d=p[1];this.ctx.save(),this.ctx.lineWidth=o||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()}},e.prototype.drawCtrlList=function(t){var e=this;t.ctrlsData.forEach((function(t,i){e.drawCtrl(t)}))},e.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()},e.prototype.setImage=function(e){this.image.src=e,this.image.crossOrigin="anonymous",this.canvas.style.backgroundImage='url("'.concat(e,'")'),this.canvas.style.backgroundSize="contain",this.canvas.style.backgroundRepeat="no-repeat",this.canvas.style.backgroundPosition="center center",this.image.onload=function(){h.emit(t.EventType.Load)}},e.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)},e.prototype.mergeEvent=function(t){var e=0,s=0,a=0,n=0;if(c()){var o=t.touches[0],r=o.clientX,h=o.clientY,p=t.target.getBoundingClientRect(),u=p.left,d=p.top;if(e=Math.round(r-u),s=Math.round(h-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-r)/2+r)-u),n=Math.round(Math.abs((I-h)/2+h)-d)}}else e=t.offsetX,s=t.offsetY;return i(i({},t),{mouseX:e,mouseY:s,mouseCX:a,mouseCY:n})},e.prototype.isPointInCircle=function(t,e,i){var s=t[0],a=t[1],n=e[0],o=e[1];return Math.sqrt(Math.pow(n-s,2)+Math.pow(o-a,2))<=i},e.prototype.isPointInRect=function(t,e){var i=t[0],s=t[1],a=e[0],n=a[0],o=a[1],r=e[1],h=r[0],c=r[1];return n<=i&&i<=h&&o<=s&&s<=c},e.prototype.isHitOnShape=function(e){for(var i=this.dataset.length-1;i>=0;i--){var s=this.dataset[i];if(s.type===t.ShapeType.rect&&this.isPointInRect(e,s.coor))return{isOnShape:!0,index:i,shape:s}}return{isOnShape:!1,index:-1,shape:null}},e.prototype.changeCursor=function(t){this.canvas.style.cursor=t},e}();t.default=u,Object.defineProperty(t,"__esModule",{value:!0})}));