鍓嶈█涔嬪墠鍋氫簡涓€涓敾鏉匡紝杩唬浜嗕袱涓増鏈紝浣嗘槸鏃㈢劧鏄敾鏉匡紝濡傛灉鍙湁涓€涓敾绗旂殑璇濆氨澶崟璋冧簡銆傚叡鏈?绉嶆牱寮忥紝鍖呮嫭6绉嶅熀鏈牱寮忋€傚綋鐒讹紝鏈変簡涓€浜涙兂娉曚箣鍚庯紝鍚庣画杩樹細缁х画澧炲姞銆傛垜灏嗗湪鏈枃璇︾粏浠嬬粛瀹炵幇鎬濊矾鍜屽叿浣撲唬鐮併€?娆鹃鏍煎寘鎷細鍩烘湰娆惧崟鑹茶崸鍏夊鑹茬瑪鍒峰柗闆捐湣绗旀场娉¢瑙堥瑙堝湴鍧€锛歨ttps://songlh.top/paint-board/婧愪唬鐮侊細https://github.com/LHRUN/paint-board娆㈣繋toStar猸愶笍鍩烘湰鍗曡壊绗斿埛鐨勫熀鏈疄鐜般€傞櫎浜嗙偣涓庣偣涔嬮棿鐨勮仈绯伙紝杩橀渶瑕佹敞鎰忎袱鐐广€傞鍏堣绠楅紶鏍囩Щ鍔ㄦ椂鐨勫綋鍓嶇Щ鍔ㄩ€熷害锛岀劧鍚庢牴鎹€熷害璁$畻绾垮锛岃繖鏄负浜嗗疄鐜伴紶鏍囩Щ鍔ㄥ揩锛岀嚎瀹戒細鍙樼獎锛岀Щ鍔ㄦ參锛岀嚎瀹戒細鎭㈠姝e父銆備负浜嗛伩鍏嶇洿绾胯繛鎺ョ偣鐨勪笉鑹奖鍝嶏紝鎴戜細浣跨敤璐濆灏旀洸绾胯繘琛岃繛鎺?***榧犳爣绉诲姩鏃舵坊鍔犳柊鍧愭爣*@paramposition*/addPosition(position:MousePosition){this.positions.push(position)//澶勭悊褰撳墠绾垮if(this.positions.length>1){//璁$畻绉诲姩閫熷害constmouseSpeed=this._computedSpeed(this.positions[this.positions.length-2],this.positions[this.positions.length-1])//璁$畻绾垮constlineWidth=this._computedLineWidth(mouseSpeed)this.lineWidths.push(lineWidth)}}/***璁$畻绉诲姩閫熷害*@paramstart璧风偣*@paramend缁堢偣*/_computedSpeed(start:MousePosition,end:MousePosition){//鑾峰彇璺濈constmoveDistance=getDistance(start,end)constcurTime=鏃ユ湡銆俷ow()//鑾峰彇绉诲姩闂撮殧lastMoveTime:鏈€鍚庝竴娆¢紶鏍囩Щ鍔ㄦ椂闂碿onstmoveTime=curTime-this.lastMoveTime//璁$畻閫熷害constmouseSpeed=moveDistance/moveTime//鏇存柊鏈€鍚庝竴娆$Щ鍔ㄦ椂闂磘his.lastMoveTime=curTimereturnmouseSpeed}/***璁$畻绗斿埛瀹藉害*@paramspeed榧犳爣绉诲姩閫熷害*/_computedLineWidth(speed:number){letlineWidth=0constminWidth=this.minWidthconstmaxWidth=this.maxWidthif(speed>=this.maxSpeed){lineWidth=minWidth}elseif(speed<=this.minSpeed){lineWidth=maxWidth}else{lineWidth=maxWidth-(speed/this.maxSpeed)*maxWidth}lineWidth=lineWidth*(1/3)+this.lastLineWidth*(2/3)this.lastLineWidth=lineWidthreturnlineWidth}娓叉煋鏃堕亶鍘嗘墍鏈夊潗鏍?***鑷敱鐢荤瑪娓叉煋*@paramcontextcanvas2D娓叉煋涓婁笅鏂?@paraminstanceFreeDraw*/functionfreeDrawRender(context:CanvasRenderingContext2D,instance:FreeLine){context.save()context.lineCap='round'context.lineJoin='round'switch(instance.style){//鐜板湪鍙湁鍩烘湰鐨勭瑪鍒凤紝涓嶅悓鐨刢鍚庨潰浼氬姞鍏ヤ綔涓烘渚婩reeDrawStyle.Basic:context.strokeStyle=instance.colors[0]breakdefault:break}for(leti=1;ivoid){const{positions,lineWidths}=instanceconst{x:centerX,y:centerY}=positions[i-1}]const{x:endX,y:endY}=positions[i]涓婁笅鏂?beginPath()if(i==1){context.moveTo(centerX,centerY)context.lineTo(endX,endY)}else{const{x:startX,y:startY}=positions[i-2]甯搁噺lastX=(startX+centerX)/2甯搁噺lastY=(startY+centerY)/2甯搁噺x=(centerX+endX)/2甯搁噺y=(centerY+endY)/2context.moveTo(lastX,lastY)context.quadraticCurveTo(centerX,centerY,x,y)}context.lineWidth=lineWidths[i]cb?.(instance,i,context)context.stroke()}鑽у厜鑽у厜鍙渶瑕佸湪鍩虹鏍峰紡鍑芥暟freeDrawRender(context:CanvasRenderingContext2D,instance:FreeLine){context.save()context.lineCap='round'context.lineJoin='round'switch(instance.style){//...//鑽у厜澧炲姞闃村奖鏁堟灉caseFreeDrawStyle.Shadow:context.shadowColor=instance.colors[0]context.strokeStyle=instance.colors[0]breakdefault:break}for(leti=1;i{context.shadowBlur=instance.lineWidths[i]})breakdefault:break}}context.restore()}澶氳壊绗斿埛澶氳壊绗斿埛闇€瑕佷娇鐢╟ontext.createPattern锛岃繖涓猘pi鍙互閫氳繃canvas鍒涘缓涓€涓寚瀹氱殑妯℃澘锛岀劧鍚庤杩欎釜妯℃澘鍦ㄦ寚瀹氱殑鏂瑰悜涓婇噸澶峬etaimage銆傚叿浣撲娇鐢ㄦ柟娉曡鍙傝€僊DN/***FreeBrushRendering*@paramcontextcanvas浜岀淮娓叉煋涓婁笅鏂?@paraminstanceFreeDraw*@parammaterialbrushmaterial*/exportconstfreeDrawRender=(context:CanvasRenderingContext2D,instance:FreeDraw,material:Material)=>{context.save()context.lineCap='round'context.lineJoin='round'switch(instance.style){//...//澶氳壊鐢荤瑪鐩扚reeDrawStyle.MultiColor:context.strokeStyle=getMultiColorPattern(instance.colors)breakdefault:break}for(leti=1;i{constcanvas=document.createElement('canvas')constcontext=canvas.getContext('2d')asCanvasRenderingContext2DconstCOLOR_WIDTH=5//姣忕棰滆壊鐨勫搴anvas.width=COLOR_WIDTH*colors.lengthcanvas.height=20colors.forEach((color,i)=>{context.fillStyle=colorcontext.fillRect(COLOR_WIDTH*i,0,COLOR_WIDTH,20)})returncontext.createPattern(canvas,'repeat')asCanvasPattern}鍠烽浘鏄痑涓€涓被浼奸洩鑺辩殑鏁堟灉锛屽湪榧犳爣绉诲姩璺緞涓婇殢鏈虹粯鍒讹紝浣嗘槸鍒氬紑濮嬪啓鐨勬椂鍊欏彂鐜板鏋滄瘡涓偣閮借褰曢殢鏈洪洩鑺辩偣鐒跺悗缂撳瓨锛屽唴瀛樺崰鐢ㄥお澶э紝浜庢槸灏濊瘯鐢熸垚5棰勫厛灏嗕笉鍚岀粍鐨勬暟鎹紝鎸夐『搴忔樉绀猴紝涔熷彲浠ュ疄鐜伴殢鏈烘晥鏋?lineJoin='round'switch(instance.style){//...//鍠锋秱妗堜緥FreeDrawStyle.Spray:context.fillStyle=instance.colors[0]breakdefault:break}for(leti=1;i{const{x,y}=瀹炰緥銆俻ositions[i]for(letj=0;j<50;j++){/***sprayPoint鏄垜鎻愬墠鐢熸垚鐨?缁勯殢鏈哄柗娲掓暟鎹紝渚濇鏄剧ず*{*angleradian*radiusradius*alphatransparency*}*/const{瑙掑害锛屽崐寰勶紝alpha}=sprayPoint[i%5][j]context.globalAlpha=alphaconstdistanceX=radius*Math.cos(angle)constdistanceY=radius*Math.sin(angle)//鏍规嵁瀹藉害闄愬埗鍠烽浘鐨勫搴︼紝鍥犱负鍠烽浘澶粏涓嶅ソ鐪嬶紝鎵€浠ユ垜鍔犲€峣f(distanceX-instance.lineWidths[i]*2&&distanceY>-instance.lineWidths[i]*2){context.fillRect(x+distanceX,y+distanceY,2,2)}}}铚$瑪铚$瑪鏁堟灉涔熸槸鐢ㄥ埌浜哻ontext.createPattern銆傞鍏堬紝鎴戜娇鐢ㄥ綋鍓嶇敾绗旈鑹蹭綔涓哄簳鑹诧紝鐒跺悗鐢ㄧ綉涓婃壘鐨勪竴绉嶈湣绗旀潗璐ㄧ殑閫忔槑鍥剧墖瑕嗙洊銆備互涓婏紝鍙互瀹炵幇铚$瑪鏁堟灉/***鑷敱鐢荤瑪娓叉煋*@paramcontextcanvas浜岀淮娓叉煋涓婁笅鏂?@paraminstanceFreeDraw*@parammaterial鐢荤瑪鏉愯川*/exportconstfreeDrawRender=(context:CanvasRenderingContext2D,instance:FreeDraw,material:Material)=>{context.save()context.lineCap='round'context.lineJoin='round'switch(instance.style){//...//铚$瑪鐩扚reeDrawStyle.Crayon:context.strokeStyle=getCrayonPattern(instance.colors[0],material.crayon)breakdefault:break}for(leti=1;i{constcanvas=document.createElement('canvas')constcontext=canvas.getContext('2d')浣滀负CanvasRenderingContext2Dcanvas.width=100鐢诲竷.height=100context.fillStyle=colorcontext.fillRect(0,0,100,100)if(crayon){context.drawImage(crayon,0,0,100,100)}returncontext.createPattern(canvas,'repeat')asCanvasPattern}褰撴皵娉¢紶鏍囩Щ鍔ㄦ椂锛岃褰曟皵娉$殑鍗婂緞鍜岄€忔槑搴︺€傛覆鏌撴椂锛屼娇鐢╟ontext.arc鐢讳竴涓渾銆俛ddPosition(position:MousePosition){//...//璁板綍姘旀场鐨勫崐寰勫拰閫忔槑搴f(this.style===FreeDrawStyle.Bubble&&this.bubbles){this.bubbles.push({//getRandomIntGet鑼冨洿鍐呯殑闅忔満鏁存暟鍗婂緞锛歡etRandomInt(this.minWidth*2,this.maxWidth*2),//閫忔槑搴pacity:Math.random()})}//...}/***drawbubble*@paraminstanceFreeDrawinstance*@paramisubscript*@paramcontextcanvas浜岀淮娓叉煋涓婁笅鏂?/const_drawBubble=(instance:FreeDraw,i:number,涓婁笅鏂囷細CanvasRenderingContext2D)=>{context.beginPath()if(instance.bubbles){const{x,y}=instance.positions[i]context.globalAlpha=instance.bubbles[i].opacitycontext.arc(x,y,instance.bubbles[i].radius,0,Math.PI*2,false)context.fill()}}鎬荤粨濡傛灉澶у鍙戠幇闂鎴栬€呮湁濂界殑瑙e喅鍔炴硶锛屾杩庤璁吼煈荤敾鏉跨郴鍒楁枃绔狅細鍩轰簬oncanvas澶氬姛鑳界敾鏉縞anvas鐢绘澘缁樼敾鍏冪礌鐨勭敾妗嗛€夋嫨鍙傝€冭祫鏂欐帰绱㈢敾甯冪粯鐢绘妧宸?/p>