0xbae9802a…81c7sent to0x096451f4…6ee3·#16,981,799·view on Etherscan
intart_the_metrolet theMetro=e=>{let t=new Random(e.seed),n={inverseScaleBase:1,inverseScaleConstant:2,autoScaleCanvas:!0,stopRadius:2.5,lineWidth:2,wagonWidth:1,stopWidth:1.5,lineSeperationScale:1.5,wagonStrokeScale:2.8,metroLineId:0,metroLines:[],metroLinePaths:[],metroLineGroups:[],flatStops:[],wagons:[],metroLineSize:{},metroLineCenter:{},metroLineScale:1,minViewScale:1,viewScale:1,targetMetroLineScale:1,pointerOffsetX:0,pointerOffsetY:0,pointerDown:!1,pointerDownX:0,pointerDownY:0,pointerX:0,pointerY:0,targetCameraX:0,targetCameraY:0,cameraX:0,cameraY:0,cameraDownX:0,cameraDownY:0,pickedWagon:void 0,wagonsEnabled:!0,zoomEnabled:!1,zoomScale:5,isZoomedIn:!1,isInIdleMode:!1,smoothness:0,targetSmoothness:0,idleModeTimer:0,idleModeChangeCount:0,isFinished:!1};(()=>{if(Object.keys(e).forEach((t=>{n[t]=e[t]})),e.canvas?n.canvas=e.canvas:(_sb.createMainCanvas(),n.canvas=_sb.mainCanvas),n.ctx=n.canvas.getContext("2d"),n.canvas.style.touchAction="none",n.canvas.style.width="100%",n.canvas.style.height="100%",e.pixelRatio?n.pScale=e.pixelRatio:n.pScale=window.devicePixelRatio,!e.ignoreMetaTag){let e=document.createElement("meta");e.name="viewport",e.content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0",document.getElementsByTagName("head")[0].appendChild(e)}n.theme=e.theme,(!n.theme.ls||n.theme.ls&&0==n.theme.ls.length)&&(n.theme.ls=n.theme.b)})();let o,i,a=(e,t)=>{let o=n.theme.lineColors.filter((t=>t[0]==e));return 1==o.length?o[0]:o[t%o.length]},r=({x:e,y:t,x1:o,y1:i,width:a,color:r})=>{n.ctx.beginPath(),n.ctx.moveTo(e,t),n.ctx.lineTo(o,i),n.ctx.globalAlpha=1,n.ctx.strokeStyle=r,n.ctx.lineCap="round",n.ctx.lineWidth=a,n.ctx.stroke()},s=({x:e,y:t,x1:n,y1:o,width:i,stroke:a,color:s,strokeColor:l})=>{r({x:e,y:t,x1:n,y1:o,width:a,color:l}),r({x:e,y:t,x1:n,y1:o,width:i,color:s})},l=e=>e.x+""+e.y,c=(e,t)=>{let n=(e=>{let t=2*Math.PI;for(e%=t;e<0;)e+=t;return e})(e-t);return 90==Math.floor(180*n/Math.PI)},h=(e,t)=>e.x==t.x||e.y==t.y,d=(e,t)=>e*(n.viewScale*n.metroLineScale+n.inverseScaleBase/(n.viewScale*n.metroLineScale)*n.inverseScaleConstant*t),m=(e,t)=>{let n=g(t.stop0,t.stop1)+.5*Math.PI,o=t.indexes[e.id]-(t.lineCount-1)/2;return{x:Math.cos(n)*o,y:Math.sin(n)*o}},g=(e,t)=>{let n=e.x-t.x,o=e.y-t.y;return Math.atan2(o,n)},p=(e,t)=>{let n=[e.ox+""+e.oy,t.ox+""+t.oy];return n.sort(),n.join("")},u=(e,t,o,i)=>({x:e.x+i*Math.cos(t-Math.PI/2)*o*d(n.lineWidth+.5*n.lineSeperationScale,0)*.5,y:e.y+i*Math.sin(t-Math.PI/2)*o*d(n.lineWidth+.5*n.lineSeperationScale,0)*.5}),x=e=>{e.forEach((e=>{let t=1;if(e.stopScale>1&&(t=.6*e.stopScale),e.stopScale<3)(({x:e,y:t,r:o,width:i})=>{n.ctx.beginPath(),n.ctx.arc(e,t,o,0,2*Math.PI),n.ctx.lineWidth=i,n.ctx.fillStyle=n.theme.sf,n.ctx.strokeStyle=n.theme.ss,n.ctx.fill(),n.ctx.stroke()})({x:e.x,y:e.y,r:d(n.stopRadius*t,0),width:n.stopWidth*(n.metroLineScale*n.viewScale)});else if(t=1,e.massiveConnections.length>1)e.massiveConnections.forEach((o=>{let i=u(e,o.angle,o.count,1),a=u(e,o.angle,o.count,-1);r({x:i.x,y:i.y,x1:a.x,y1:a.y,width:d(2*n.stopWidth*t+3,0),color:n.theme.ss})})),e.massiveConnections.forEach((o=>{let i=u(e,o.angle,o.count,1),a=u(e,o.angle,o.count,-1);r({x:i.x,y:i.y,x1:a.x,y1:a.y,width:d(2*n.stopWidth*t,0),color:n.theme.sf})}));else if(e.crossPairs)e.crossPairs.forEach((o=>{let i=u(e,o.angle,o.count,1),a=u(e,o.angle,o.count,-1);r({x:i.x,y:i.y,x1:a.x,y1:a.y,width:d(2*n.stopWidth*t+3,0),color:n.theme.ss})})),e.crossPairs.forEach((o=>{let i=u(e,o.angle,o.count,1),a=u(e,o.angle,o.count,-1);r({x:i.x,y:i.y,x1:a.x,y1:a.y,width:d(2*n.stopWidth*t,0),color:n.theme.sf})}));else{let o=u(e,e.biggestAngle.angle,e.biggestAngle.count,1),i=u(e,e.biggestAngle.angle,e.biggestAngle.count,-1);s({x:o.x,y:o.y,x1:i.x,y1:i.y,width:d(2*n.stopWidth*t,0),stroke:d(2*n.stopWidth*t+3,0),color:n.theme.sf,strokeColor:n.theme.ss})}}))},w=e=>{if(!n.wagonsEnabled)return;let t=d(.8*n.lineWidth,0),o=d(.8*n.lineWidth*n.wagonStrokeScale,0),i=o,a=d(n.wagonWidth,0),r=a,l=S(e);e.order=l.order,l.progress>.7?(r=a*Math.abs(1-l.progress)/.3,i=o*Math.abs(1-l.progress)/.1):l.progress<.3?(r=a*(1-Math.abs(l.progress-.3)/.3),i=o*(1-Math.abs(l.progress-.1)/.1)):(r=a,i=o),l.progress>.9?i=o*Math.abs(1-l.progress)/.1:l.progress<.1?i=o*(1-Math.abs(l.progress-.1)/.1):(r=a,i=o);let c=Math.cos(l.angle)*r+l.x,h=Math.sin(l.angle)*r+l.y,m=Math.cos(l.angle)*-r+l.x,g=Math.sin(l.angle)*-r+l.y;s({x:c,y:h,x1:m,y1:g,width:t,stroke:i,color:e.metroLine.color[1],strokeColor:e.metroLine.color[0]}),e.progress>100?(e.waitProgress+=e.speed,e.waitProgress>105&&(e.progress=0,e.waitProgress=0,e.currentPath.wagons=e.currentPath.wagons.filter((t=>t!=e)),e.direction?(e.index++,e.index==e.metroLine.paths.length&&(e.index=e.metroLine.paths.length-1,e.direction=0)):(e.index--,e.index<0&&(e.index=0,e.direction=1)),e.currentPath=e.metroLine.paths[e.index],e.metroLine.paths[e.index].wagons.push(e))):e.progress+=e.speed},y=e=>{let t=(e=>{let t={x:1e13,y:1e13,r:0,b:0};return n.metroLineCenter={x:0,y:0},e.forEach((e=>{e.stops.forEach((e=>{t.x=Math.min(t.x,e.x),t.y=Math.min(t.y,e.y),t.r=Math.max(t.r,e.x),t.b=Math.max(t.b,e.y),e.ox=e.x,e.oy=e.y,n.metroLineCenter.x+=e.x,n.metroLineCenter.y+=e.y}))})),t})(e);n.metroLineCenter.x=.5*Math.floor(t.r-t.x)+t.x,n.metroLineCenter.y=.5*Math.floor(t.b-t.y)+t.y,n.metroLineSize.width=Math.abs(t.r-t.x),n.metroLineSize.height=Math.abs(t.b-t.y),n.metroLineSize.maxSize=Math.max(n.metroLineSize.width,n.metroLineSize.height),n.metroLineSize.volume=n.metroLineSize.width*n.metroLineSize.height},S=e=>{let t,o,i=e=>-(Math.cos(Math.PI*e)-1)/2,a=d(n.lineWidth,.1),r=e.metroLine.paths[e.index],s=r.lines[e.metroLine.id].stop0,l=r.lines[e.metroLine.id].stop1,c=m(e.metroLine,r);return c.x*=a*n.lineSeperationScale,c.y*=a*n.lineSeperationScale,e.direction?(t={x:s.x+c.x,y:s.y+c.y},o={x:l.x+c.x,y:l.y+c.y}):(o={x:s.x+c.x,y:s.y+c.y},t={x:l.x+c.x,y:l.y+c.y}),{x:t.x+i(e.progress/100)*(o.x-t.x),y:t.y+i(e.progress/100)*(o.y-t.y),angle:g(t,o),progress:e.progress/100,order:r.lineCount}},L=(e,n,o,i)=>({metroLine:e,progress:100*t.random_dec(),waitProgress:0,speed:n,index:o,direction:i,order:0,currentPath:e.paths[o]}),f=()=>{if(n.isFinished||window.requestAnimationFrame(f),M(),n.targetSmoothness=n.isInIdleMode?.005:.1,n.smoothness+=.01*(n.targetSmoothness-n.smoothness),n.isInIdleMode&&n.pickedWagon){let e=S(n.pickedWagon);n.targetCameraX=-(e.x-n.pointerOffsetX)+.5*n.canvas.width,n.targetCameraY=-(e.y-n.pointerOffsetY)+.5*n.canvas.height}var e,t;n.metroLineScale+=(n.targetMetroLineScale-n.metroLineScale)*n.smoothness,n.cameraX+=(n.targetCameraX-n.cameraX)*n.smoothness,n.cameraY+=(n.targetCameraY-n.cameraY)*n.smoothness,n.pointerOffsetX=n.cameraX,n.pointerOffsetY=n.cameraY,((e,t)=>{let o=.5*n.canvas.width,i=.5*n.canvas.height,a=o-n.metroLineCenter.x*(n.metroLineScale*n.viewScale),r=i-n.metroLineCenter.y*(n.metroLineScale*n.viewScale);e.forEach((e=>{e.stops.forEach(((e,t)=>{e.x=e.ox*(n.metroLineScale*n.viewScale)+a+n.pointerOffsetX,e.y=e.oy*(n.metroLineScale*n.viewScale)+r+n.pointerOffsetY}))}))})(n.metroLines,n.flatStops),n.ctx.beginPath(),n.ctx.rect(0,0,n.canvas.width,n.canvas.height),n.ctx.fillStyle=n.theme.b,n.ctx.fill(),e=n.metroLines,t=n.metroLinePaths,n.wagons,t.forEach((t=>{t.lineList.forEach((o=>{let i=e[o.metroLineId],a=d(n.lineWidth,.1),l=o.stop0,c=o.stop1,h=m(i,t);h.x*=a*n.lineSeperationScale,h.y*=a*n.lineSeperationScale;let g=n.theme.ls;g&&g.length>0?s({x:l.x+h.x,y:l.y+h.y,x1:c.x+h.x,y1:c.y+h.y,width:a,stroke:2*a,color:i.color[0],strokeColor:g}):r({x:l.x+h.x,y:l.y+h.y,x1:c.x+h.x,y1:c.y+h.y,width:a,color:i.color[0]})})),t.wagons.forEach((e=>{w(e)}))})),x(n.flatStops),n.onRender&&n.onRender()},v=()=>{e.svgData?n.metroLines=(e=>{let t=e.split("<symbol id='group'")[1].split("</symbol")[0].split("<path d='M"),o=[];for(let e=1;e<t.length;e++){let i=t[e].split("' stroke='"),r=i[0],s=i[1].split("'/>")[0],l=r.split(" "),c=[];for(let e=0;e<l.length;e+=2){let t=parseInt(l[e]),n=parseInt(l[e+1]);c.push({x:t,y:n})}let h=e=>c[e];c.forEach(((e,t)=>{e.n||(e.n=[]),0==t?c[0].n.push(1):t<c.length-1?(c[t].n.push(t-1),c[t].n.push(t+1)):t==c.length-1&&c[t].n.push(t-1)})),o.push({stops:c,id:n.metroLineId,color:a(s,n.metroLineId),getStop:h}),n.metroLineId++}return o})(e.svgData):n.metroLines=(e=>{let t=[];return e.forEach((e=>{let o=[];e.stops.forEach((e=>{o.push({x:e.x,y:e.y})})),o.forEach(((e,t)=>{e.n||(e.n=[]),0==t?o[0].n.push(1):t<o.length-1?(o[t].n.push(t-1),o[t].n.push(t+1)):t==o.length-1&&o[t].n.push(t-1)})),t.push({stops:o,id:n.metroLineId,color:a(e.color,n.metroLineId),getStop:e=>o[e]}),n.metroLineId++})),t})(e.data),n.flatStops=(e=>{let t={},n=0;e.forEach((e=>{e.stops.forEach(((o,i)=>{let a=l(o);if(t[a]){t[a].lineIds.includes(e.id)||t[a].lineIds.push(e.id);let n=o.n.map((n=>{let i=e.getStop(n),r=e.id+""+l(i),s=g(o,i),c=h(i,o);return t[a].outGoingDirections[s]?(t[a].outGoingDirections[s].count++,t[a].outGoingDirections[s].count>t[a].maxDirectionAngle.count&&(t[a].maxDirectionAngle={angle:s,count:t[a].outGoingDirections[s].count})):(t[a].totalDifferentOutgoinDirection++,t[a].outGoingDirections[s]={count:1,isAngular:c}),t[a].maxDirection=Math.max(t[a].outGoingDirections[s].count,t[a].maxDirection),t[a].maxDirection>1?t[a].stopScale=1.2*t[a].maxDirection:t[a].stopScale=t[a].maxDirection,{id:r,metroLine:e.id,direction:s,indexInLine:n,stop:i}}));t[a].neighbours=t[a].neighbours.concat(n),e.stops[i]=t[a]}else{let r={},s=0,c=0,d={};t[a]={id:n,x:o.x,y:o.y,ox:o.x,oy:o.y,lineIds:[e.id],outGoingDirections:{},stopScale:1,neighbours:o.n.map((t=>{let n=e.getStop(t),i=e.id+"_"+l(n),a=g(o,n),m=h(n,o);return r[a]?(r[a].count++,r[a].count>d.count&&(d={angle:a,count:r[a].count,stop0:o,stop1:n})):(s++,d={angle:a,count:1},r[a]={count:1,isAngular:m}),c=Math.max(r[a].count,c),{id:i,metroLine:e.id,direction:a,indexInLine:t,stop:n,maxDirectionAngle:d}}))},t[a].outGoingDirections=r,t[a].totalDifferentOutgoinDirection=s,t[a].maxDirection=c,t[a].maxDirectionAngle=d,e.stops[i]=t[a],n++}}))}));let o=Object.values(t);return o.forEach((e=>{let t=Object.keys(e.outGoingDirections),n=[],o=[];t.forEach((t=>{let i=e.outGoingDirections[t].isAngular,a=e.outGoingDirections[t].count;a>2&&n.push({angle:t,count:a,isAngular:i}),a>3&&o.push({angle:t,count:a})})),n.sort(((e,t)=>{let n=Math.pow(e.count,3)+(e.isAngular?5:0);return Math.pow(t.count,3)+(t.isAngular?5:0)-n}));let i=!1,a=[];n.forEach((e=>{n.forEach((t=>{c(e.angle,t.angle)&&e!=t&&(i=!0,a.push({connection1:e,connection2:t}))}))})),a.sort(((e,t)=>e.connection1.count+e.connection2.count-(t.connection1.count+t.connection2.count))),e.hasAngularDirection=!1,e.angularDirectionAngle=0,e.bigConnections=n,e.hasAnyCross=i,e.massiveConnections=o,a.length>0&&(e.crossPairs=[a[0].connection1,a[0].connection2]),n.length>0?e.biggestAngle={angle:n[0].angle,count:n[0].count}:e.biggestAngle={angle:e.maxDirectionAngle.angle,count:e.maxDirectionAngle.count}})),o})(n.metroLines),y(n.metroLines),n.metroLinePaths=(e=>{let t={};e.forEach((e=>{e.paths=[];for(let n=0;n<e.stops.length-1;n++){let o=e.stops[n],i=e.stops[n+1],a=p(o,i);if(t[a]){let n={metroLineId:e.id,stop0:o,stop1:i,angle:g(o,i)};n.stop0=o,n.stop1=i,n.isAngular=h(o,i),t[a].lines[e.id]=n}else{let n={lines:[],wagons:[]};n.lines[e.id]={metroLineId:e.id,stop0:o,stop1:i,angle:g(o,i)},n.stop0=o,n.stop1=i,n.isAngular=h(o,i),t[a]=n}e.paths.push(t[a])}})),e.forEach((e=>{e.paths.forEach((t=>{let n=Object.keys(t.lines);n.sort(((e,t)=>e.metroLineId>t.metroLineId));let o=n.indexOf(e.id.toString());t.indexes||(t.indexes={}),t.lineCount=n.length,t.indexes[e.id]=o}))}));let n=Object.values(t);return n.forEach((e=>{e.lineList=Object.values(e.lines)})),n.sort(((e,t)=>Math.pow(e.lineCount,3)+(e.isAngular?1:0)-(Math.pow(t.lineCount,3)+(t.isAngular?1:0)))),n})(n.metroLines),n.wagons=(e=>{let n=[];return e.forEach((e=>{let o=.6*t.random_dec()+.2,i=L(e,o,0,1),a=L(e,o,e.stops.length-2,0);if(i.currentPath.wagons.push(i),a.currentPath.wagons.push(a),n.push(i),n.push(a),e.stops.length>6){let t=L(e,o,Math.floor((e.stops.length-1)/2),1),i=L(e,o,Math.floor((e.stops.length-1)/2),0);t.currentPath.wagons.push(t),i.currentPath.wagons.push(i),n.push(t),n.push(i)}})),n})(n.metroLines)},M=()=>{if(o==window.innerWidth&&i==window.innerHeight)return;o=window.innerWidth,i=window.innerHeight,n.autoScaleCanvas&&(n.canvas.width=window.innerWidth*n.pScale,n.canvas.height=window.innerHeight*n.pScale);let e=0;e=n.canvas.width/n.canvas.height>n.metroLineSize.width/n.metroLineSize.height?n.canvas.height/n.metroLineSize.height*.7:n.canvas.width/n.metroLineSize.width*.7,n.targetCameraX*=e/n.viewScale,n.targetCameraY*=e/n.viewScale,n.cameraX*=e/n.viewScale,n.cameraY*=e/n.viewScale,n.minViewScale=e,n.viewScale=e,n.viewScale<2&&(n.zoomEnabled=!0)},C=e=>{n.zoomEnabled&&(n.isZoomedIn||n.isInIdleMode?(n.targetMetroLineScale=1,n.targetCameraX=0,n.targetCameraY=0,n.pickedWagon=void 0,n.isZoomedIn=!1,b()):(D(),n.targetCameraX=(.5*window.innerWidth-n.pointerX)/(n.viewScale*n.metroLineScale)*(n.zoomScale*n.pScale),n.targetCameraY=(.5*window.innerHeight-n.pointerY)/(n.viewScale*n.metroLineScale)*(n.zoomScale*n.pScale),n.targetMetroLineScale=1/n.minViewScale*n.zoomScale,n.isZoomedIn=!0))},I=()=>{n.zoomEnabled&&(n.smoothness=.005,n.targetMetroLineScale=1/n.minViewScale*n.zoomScale,n.pickedWagon=t.random_choice(n.wagons),n.isInIdleMode=!0,n.isZoomedIn=!1,E())},b=()=>{D(),n.pickedWagon=null,isIdleModeChanging=!1,n.idleModeChangeCount=0,n.isInIdleMode=!1,n.idleModeTimer=setTimeout((()=>{I()}),1e4)},D=()=>{n.isInIdleMode=!1,n.idleModeTimer&&clearInterval(n.idleModeTimer)},E=()=>{n.idleModeTimer&&clearInterval(n.idleModeTimer),n.idleModeChangeCount++,n.idleModeTimer=setTimeout((()=>{n.idleModeChangeCount>2?X():I()}),35e3)},X=()=>{n.targetMetroLineScale=1,n.idleModeChangeCount=0,n.pickedWagon=void 0,n.targetCameraX=0,n.targetCameraY=0,n.isZoomedIn=!1,D(),n.idleModeTimer=setTimeout((()=>{I()}),3e4)},Y=!1,W=e=>{if(n.pointerDown=!0,n.pointerX=e.pageX,n.pointerY=e.pageY,n.pointerDownX=n.pointerX,n.pointerDownY=n.pointerY,n.cameraDownX=n.cameraX,n.cameraDownY=n.cameraY,!Y)return Y=!0,setTimeout((function(){Y=!1}),300),!1;e.preventDefault(),C()},k=e=>{n.pointerDown=!1},P=e=>{if(n.pointerX=e.pageX,n.pointerY=e.pageY,doubleTap=!1,n.pointerDown){if(n.isInIdleMode&&(D(),C()),!n.isZoomedIn)return;n.cameraX=n.cameraDownX-2*(n.pointerDownX-e.pageX),n.cameraY=n.cameraDownY-2*(n.pointerDownY-e.pageY),n.targetCameraX=n.cameraX,n.targetCameraY=n.cameraY}},A=e=>{87===e.keyCode&&(n.wagonsEnabled=!n.wagonsEnabled),83===e.keyCode&&(e=>{let t=document.createElement("a");t.href=e,t.download="themetro",document.body.appendChild(t),t.click()})(n.canvas.toDataURL("image/png"))},z=!1,T=()=>{z||(z=!0,v(),f(),n.metroLineScale=1,n.viewScale=n.minViewScale,n.targetMetroLineScale=n.metroLineScale,n.pointerX=.5*window.innerWidth,n.pointerY=.5*window.innerHeight,b(),window.addEventListener("pointerdown",W),window.addEventListener("pointerup",k),window.addEventListener("pointermove",P),window.addEventListener("keydown",A))},O=()=>{0==n.canvas.width||0==n.canvas.height||0==window.innerWidth||0==window.innerHeight?setTimeout((()=>{O()}),10):T()};return n.start=()=>{window&&window.addEventListener("load",(()=>{O()}))},n.finish=()=>{n.isFinished=!0,window.removeEventListener("pointerdown",W),window.removeEventListener("pointerup",k),window.removeEventListener("pointermove",P),window.removeEventListener("keydown",A),D()},n};