Extend and optimize

1. Image smoothing

<script>
    const canvas=document.getElementById('canvas');
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const ctx=canvas.getContext('2d');
    /* Image smoothing imageSmoothingEnabled*/


    /* Image source */
    const img=new Image();
    img.src='./images/chess.jpg';
    img.onload=function(){
        const {width,height}=img;
        DrawImage (image, x, y) */
        ctx.drawImage(img,100.100,width*10,height*10);
        ctx.imageSmoothingEnabled=false;
        ctx.drawImage(img,100.100+height*10,width*10,height*10);
    };

</script>
Copy the code

2. Canvas draws a line one pixel wide

<script>
    const canvas=document.getElementById('canvas');
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const ctx=canvas.getContext('2d');

    /* Draw a line */
    ctx.beginPath();
    ctx.lineWidth=1;
    ctx.moveTo(50.50);
    ctx.lineTo(400.50);
    ctx.stroke();

    /* One pixel wide line */
    /* Method 1 */
    ctx.beginPath();
    ctx.lineWidth=1;
    ctx.moveTo(50.150.5);
    ctx.lineTo(400.150.5);
    ctx.stroke();
    /* Method 2 */
    ctx.translate(0.5.0.5);
    ctx.beginPath();
    ctx.lineWidth=1;
    ctx.moveTo(50.250);
    ctx.lineTo(400.250);
    ctx.stroke();

</script>
Copy the code

3. Pixel ratio of the appropriate device

<script>
/* Adaptor device resolution */
    {
        const canvas=document.getElementById('canvas2');
        const  ctx=canvas.getContext('2d');
        // get the devicePixelRatio devicePixelRatio from the window object
        const ratio=window.devicePixelRatio;
        console.log('ratio',ratio);

        // Multiply the canvas size by the ratio of pixels, that is, make the canvas larger
        canvas.width=width*ratio;
        canvas.height=height*ratio;

        // Synchronize the canvas scale with the canvas scale
        ctx.scale(ratio,ratio);

        // Set canvas CSS size to define the visual size of the canvas
        canvas.style.width=width+'px';
        canvas.style.height=height+'px';

        / / drawing
        ctx.font='60px arial ';
        ctx.fillText('canvas'.10.100);
    }
</script>
Copy the code

4. Canvas to picture

<body>
<canvas id="canvas" width="420" height="126"></canvas>
<img id="img" src="" alt="">
<script>
    const canvas=document.getElementById('canvas');
    const ctx=canvas.getContext('2d');

    const img=new Image();
    img.src='https://img.kaikeba.com/70350130700202jusm.png';
    img.setAttribute("crossOrigin".'Anonymous');

    img.onload=function(){
        ctx.drawImage(img,0.0);
        const imgURL=canvas.toDataURL();
        console.log('imgURL',imgURL);
        document.querySelector('#img').setAttribute('src',imgURL);
    }
</script>
</body>

Copy the code

5. Ball tails

<script>
    const canvas=document.getElementById('canvas');
    const [width,height]=[window.innerWidth,window.innerHeight];
    canvas.width=width;
    canvas.height=height;
    / / brush
    const  ctx=canvas.getContext('2d');

    // Ball objectification
    class Ball{
        constructor(r,color='#00acec'){
            this.color=color;
            this.r=r;
            this.x=0;
            this.y=0;
        }
        draw(ctx){
            ctx.save();
            ctx.beginPath();
            ctx.fillStyle=this.color;
            ctx.arc(this.x,this.y,this.r,0.Math.PI*2); ctx.fill(); ctx.restore(); }}// Instantiate the ball
    let ball=new Ball(15);
    ball.y=50;
    ball.x=width/2;

    // Record the time
    let time=new Date(a);/ / gravity gravity
    const gravity=0.01;

    / / elastic
    const bounding=-0.8;

    // Speed/ms vy
    let vy=0.3;
    let vx=0.3;

    // Animation method
    function animate(){
        / / time
        let now=new Date(a);let diff=now-time;
        time=now;

        / / acceleration
        vy+=gravity;

        // Set the ball position
        ball.y+=vy*diff;
        ball.x+=vx*diff;

        // Bottom collision
        if(ball.y+ball.r>height){
            ball.y=height-ball.r;
            vy*=bounding;
        }
        // Left side collision
        if(ball.x-ball.r<0){
            ball.x=ball.r;
            vx*=bounding;
        }
        // Right side collision
        if(ball.x+ball.r>width){ ball.x=width-ball.r; vx*=bounding; }}// Render method! (function render(){
        // Set the animation
        animate();
        / / erasure
        / / CTX. ClearRect (0, 0, width, height);
        // Each drawing adds a filter mask to the previous drawing
        ctx.fillStyle='rgba (250235215,0.1)';
        ctx.fillRect(0.0,width,height);
        / / drawing
        ball.draw(ctx);
        // Recursively call the render function
        window.requestAnimationFrame(render); }) ()</script>
Copy the code

6, point to the mouse line 3d

// Create a 2d vector js file
// Vector2.js
export default class Vector2{
    constructor(x=0,y=0){
        this.x=x;
        this.y=y;
    }
    / / add the add (v)
    add(v){
        this.x+=v.x;
        this.y+=v.y;
        return this;
    }

    / / subtraction sub (v)
    sub(v){
        this.x-=v.x;
        this.y-=v.y;
        return this;
    }

    // Angle ()
    angle(){
        const {x,y}=this;
        let dir=Math.atan2(y,x);
        if(dir<0){dir+=Math.PI*2}
        return dir;
    }

    / / rotation rotate (a)
    rotate(a){
        const c=Math.cos(a);
        const s=Math.sin(a);
        const {x,y}=this;
        this.x=x*c-y*s;
        this.y=x*s+y*c;
        return this;
    }

    // Length read length()
    length(){
        const {x,y}=this;
        return Math.sqrt(x*x+y*y);
    }

    // setLength setLength(len)
    setLength(len){
        const {x,y}=this;
        const r=this.length();
        const c=x/r;
        const s=y/r;
        this.x=c*len;
        this.y=s*len;
        return this;
    }

    / / clone clone ()
    clone(){
        return new Vector2(this.x,this.y);
    }

    / / copy copy (v)
    copy(v){
        this.x=v.x;
        this.y=v.y;
        return this;
    }

    // Len length, dir direction
    static polar(len,dir){
        return new Vector2(
            Math.cos(dir)*len,
            Math.sin(dir)*len
        )
    }
}
Copy the code
<script type="module">
    import Vector2 from "./jsm/Vector2.js";

    const [width,height]=[window.innerWidth,window.innerHeight];
    const canvas=document.getElementById('canvas');
    canvas.width=width;
    canvas.height=height;
    const  ctx=canvas.getContext('2d');

    / / object
    class Line{
        constructor(start=new Vector2(),end=new Vector2()) {
            this.start=start;
            this.end=end;
        }
        draw(ctx){
            const {start,end}=this;
            ctx.save();
            / / line
            ctx.beginPath();
            ctx.moveTo(start.x,start.y);
            ctx.lineTo(end.x,end.y);
            ctx.lineWidth=2;
            ctx.stroke();
            / / dot
            ctx.beginPath();
            ctx.arc(end.x,end.y,6.0.Math.PI*2); ctx.fill(); ctx.restore(); }}// Circle object
    class Circle{
        constructor(pos,r) {
            this.pos=pos;
            this.r=r;
        }
        draw(ctx){
            const {pos,r}=this;
            ctx.save();
            ctx.setLineDash([6]);
            ctx.beginPath();
            ctx.arc(pos.x,pos.y,r,0.Math.PI*2); ctx.stroke(); ctx.restore(); }}// The base of the line
    const basicPos=new Vector2(width/2,height/2);
    // Line length
    const r1=100;
    // The radius of the circle is R2
    const r2=200;

    / / object
    const line=new Line(basicPos.clone(),new Vector2(basicPos.x+r1,basicPos.y));
    // Small circle object
    const circle1=new Circle(basicPos.clone(),r1);
    // Large circle object
    const circle2=new Circle(basicPos.clone(),r2);

    / / rendering
    render();

    window.addEventListener('mousemove',mousemoveFn);

    function mousemoveFn(event){
        // Mouse position mousePos
        const mousePos=new Vector2(event.clientX,event.clientY);
        MouseSubPos = mouseSubPos = mouseSubPos = mouseSubPos
        const mouseSubBasic=mousePos.sub(basicPos);
        // Get the distance from the mouse to the base point and calculate the ratio of this distance to the radius of the large circle
        let ratio=mouseSubBasic.length()/r2;

        // Keep the ratio no more than 1
        ratio=Math.min(ratio,1);

        // Compute the vector length len
        const len=r1*ratio;

        // Let the mouseSubBasic vector have the same length as R1
        const pos=mouseSubBasic.setLength(len);
        // Offset vector based on base point position
        pos.add(basicPos);
        // Update the end position of the line
        line.end.copy(pos);
        / / rendering
        render();
    }

    // Render method
    function render(){
        ctx.clearRect(0.0,width,height);
        line.draw(ctx);
        circle1.draw(ctx);
        circle2.draw(ctx);

    }

</script>
Copy the code

7, 404 page sight follow

<script type="module">
    import Vector2 from "./jsm/Vector2.js";

    const [width,height]=[window.innerWidth,window.innerHeight];
    const canvas=document.getElementById('canvas');
    canvas.width=width;
    canvas.height=height;
    const  ctx=canvas.getContext('2d');

    / / img loader
    const ImgLoader={
        onload(imgs,fn){
            const imgPros=imgs.map((ele) = >{
                return ImgLoader.imgPro(ele);
            });
            Promise.all(imgPros).then((val) = >{
                fn(val);
            },() = >{
                console.error('Image load failed');
            });
        },
        imgPro(img){
            return new Promise((resolve) = >{
                img.onload=function(){ resolve(img); }}); }};/ / body
    class BodyRect{
        constructor(img,pos){
            this.img=img;
            this.pos=pos;
        }
        draw(ctx){
            const {img,pos}=this; ctx.save(); ctx.drawImage(img,pos.x,pos.y); ctx.restore(); }}/ / eyes
    class EyeRect{
        constructor(img,pos,offset){
            this.img=img;
            this.pos=pos;
            this.offset=offset;
        }
        draw(ctx){
            const {img,pos,offset}=this; ctx.save(); ctx.drawImage(img,pos.x-offset,pos.y-offset); ctx.restore(); }}// The perceived distance of the eye
    const maxR=50;
    // The radius of the orbit
    const rimR=15;
    // The position of the eyes relative to the monster
    const basicPos=[new Vector2(126.52),new Vector2(219.59)];
    // The offset distance of pupil. During drawImage, the base point of the eyeball is at the upper left corner, which needs to be adjusted to the center
    const eyeR=11;
    // Body and eyes
    let monsterBody,eyeLeft,eyeRight;
    // Move the position of the transform
    let monsterPos=getMonsterPos();

    // Monster body image
    const bodyImg=new Image();
    bodyImg.src='./images/404.png';
    // Eye image
    const eyeImg=new Image();
    eyeImg.src='./images/eye.png';
    // When both images are loaded successfully, render the graphics
    ImgLoader.onload([bodyImg,eyeImg],loadedFn);


    function loadedFn(){
        // Build body and eyes
        monsterBody=new BodyRect(bodyImg,new Vector2(0.0));
        eyeLeft=new EyeRect(eyeImg,basicPos[0].clone(),eyeR);
        eyeRight=new EyeRect(eyeImg,basicPos[1].clone(),eyeR);

        / / rendering
        render();

        // Add mouse movement events
        canvas.addEventListener('mousemove',mousemoveFn);
        // Listen for window size changes
        window.addEventListener('resize',resizeFn);
    }

    // Render method
    function render(){
        / / clean up
        ctx.clearRect(0.0,width,height);
        / / rendering
        ctx.save();
        ctx.translate(monsterPos.x,monsterPos.y);
        monsterBody.draw(ctx);
        eyeLeft.draw(ctx);
        eyeRight.draw(ctx);
        ctx.restore();
    }

    // Mouse movement
    function mousemoveFn(event){
        // Get the mouse position
        const mousePos=new Vector2(event.clientX,event.clientY).sub(monsterPos);
        // Go through both eyes
        [eyeLeft,eyeRight].forEach((ele,ind) = >{
            // Get the distance from the mouse to the base point of the pupil
            const mouseSubObj=mousePos.clone().sub(basicPos[ind]);
            // Calculate the distance from the pupil to the center of the circle proportionally based on the eye center
            const radius=Math.min(mouseSubObj.length()/maxR,1)*rimR;
            // Set the pupil position
            const pos=mouseSubObj.setLength(radius).add(basicPos[ind]);
            // Assign to the position of the eye
            ele.pos.copy(pos);
        });
        / / rendering
        render();
    }

    // Get the monster location
    function getMonsterPos(){
        return new Vector2(canvas.width-500,canvas.height-500);
    }

    // Window size changes
    function resizeFn(){
        const [width,height]=[window.innerWidth,window.innerHeight];
        canvas.width=width;
        canvas.height=height;
        monsterPos=getMonsterPos();
        render();
    }
</script>
Copy the code

PutImageData and synthetic

<script>
    const [width,height]=[window.innerWidth,window.innerHeight];
    const canvas=document.getElementById('canvas');
    canvas.width=width;
    canvas.height=height;
    const  ctx=canvas.getContext('2d');

    const imgDt=ctx.createImageData(400.400);
    imgDt.data.forEach((ele,ind) = >{
        imgDt.data[ind]=255;
    })

    /* Global transparency */
    /*ctx.globalAlpha=1; CTX. PutImageData (imgDt, 0, 0); // white rectangle ctx.fillStyle='# FFF '; CTX. FillRect,0,400,400 (400); * /

    /* Path clipping */
    / / path
    /*ctx.beginPath(); CTX. Arc (400400200, 0, Math. PI * 2); ctx.stroke(); ctx.clip(); // white rectangle ctx.fillStyle='# FFF '; CTX. FillRect,0,400,400 (400); CTX. PutImageData (imgDt, 0, 0); * /

    /* Global composition */
    // Draw a graph
    /*ctx.beginPath(); CTX. Arc (400400200, 0, Math. PI * 2); ctx.fill(); //globalCompositeOperation ctx.globalCompositeOperation='source-in'; // ctx.fillStyle='# FFF '; / / CTX. FillRect,0,400,400 (400); CTX. PutImageData (imgDt, 0, 0); * /

    /*putImageData is tailored to the correct unlock method */
    // Draw a graph
    ctx.putImageData(imgDt,0.0);

    //globalCompositeOperation
    ctx.globalCompositeOperation='destination-in';

    // Draw the graph
    ctx.beginPath();
    ctx.arc(400.400.200.0.Math.PI*2);
    ctx.fill();

</script>
Copy the code

Canvas draws complex graphics

<embed id="svg"
       src="./images/mount.svg"
       width="300"
       height="300"
       type="image/svg+xml"
       pluginspage="http://www.adobe.com/svg/viewer/install/" />

<canvas id="canvas"></canvas>
<script type="module">
    const canvas=document.getElementById('canvas');
    canvas.width=300;
    canvas.height=300;
    const ctx=canvas.getContext('2d');

    // Embed Gets the SVG container
    const embed=document.querySelector('embed');

    /* When the page content is loaded successfully * getSVGDocument() gets the SVG document object in the SVG container * querySelector() gets the polygon node in the SVG document object * parsePoints() parses the vertex data in the polygon node * Draw () so vertex data, draw canvas graph * */
    window.onload=function(){
        const svgDom=embed.getSVGDocument();
        const poly=svgDom.querySelector('#poly');
        console.log('poly',poly);
        const points=parsePoints(poly.getAttribute('points'));
        console.log('points',points);
        / * * / canvas drawing
        ctx.beginPath();
        points.forEach(p= >{
            ctx.lineTo(p[0],p[1]);
        })
        ctx.fill();
    }


    /* Parses polygon * arr in SVG to cut points attributes into arrays with Spaces, such as ['x,y'... Vertice converts string points to integer points such as '1.2,2.8' → [1,3] * * */
    function parsePoints(points){
        const vertices=[];
        let arr=points.split(' ');
        for(let ele of arr){
            if(ele){
                const vertice=ele.split(', ').map((num) = >{
                    return Math.round(num); }); vertices.push(vertice); }}return vertices;
    }
</script>
Copy the code