【问题标题】:apply same JavaScript code to several canvas?将相同的 JavaScript 代码应用于多个画布?
【发布时间】:2019-11-20 01:15:35
【问题描述】:

我正在尝试将一些 JavaScript 应用于画布,所有画布都具有相同的高度和宽度属性。 由于我是 JavaScript 的初学者,而且我从来没有真正在 HTML 上操作过画布,是否可以通过简单地使用一个 JavaScript 文件来做到这一点?

我在这里发现了另一个与我的问题非常相似的问题:how to use same script.js file for calling different CSS class using multiple Ids

但即使我尝试提供的解决方案,代码仍然像以前一样损坏。

这是我用于测试的 HTML 显示

  <body>
    <div class="container" style="display: flex;">
      <div class="buttons">
        <a href="#" class="color_chane">Button 1</a>
        <canvas id="dot_1"></canvas>
      </div>
      <div class="buttons">
        <a href="#" class="color_chane">Button 2</a>
        <canvas id="dot_2"></canvas>
      </div>
      <div class="buttons">
        <a href="#" class="color_chane">Button 3</a>
        <canvas id="dot_3"></canvas>
      </div>
    </div>
  </body>

这是我用于这些按钮的 JavaScript,考虑到这是页面上唯一运行的 JavaScript,因此不同的脚本文件之间没有冲突。

/*Canvas Var*/
var nbCanvas = 3;

/*Dots variables*/
var nbDots = 20;
var weight = 60;
var net = [];
for (var i = 0; i < nbDots; i++) {
    var dot = new Dot();
    dot.setup();
    net.push(dot);
}

/* Colors var */
var index = localStorage.getItem('index') ? localStorage.getItem('index') : 0; /*save the value in the browser memory, if it already exists get it else set it to 0*/
var first = ["#4B2F73", "#8C0335", "#21EE03", "#011526", "#2960A4", "#0F0140", "#8C0444"];
var second = ["#3B2559", "#021E73", "#26C013", "#00070D", "#3E86C0", "#060126", "#591547"];
var third = ["#0A2B40", "#0442BF", "#29A619", "#024059", "#11C6D8", "#0D05F2", "#101C40"];
var fourth = ["#71C6D9", "#034C8C", "#737373", "#024959", "#BDA092", "#060273", "#011526"];
var fifth = ["#5FCDD9", "#023059", "#282828", "#3CA692", "#D83911", "#0ABF04", "#F20505"];

class Dot {
    x = 100;
    y = 100;
    radius = (canvas.width / canvas.height)/1.5;
    direction = 0;
    speed = 1;

    fillStyle(){
        index = parseInt(localStorage.getItem('index'));
        if (this.x > 4 * (context.canvas.width) / 5) {
            context.fillStyle = fifth[index];
        } else if (this.x > 3 * (context.canvas.width) / 5) {
            context.fillStyle = fourth[index];
        } else if (this.x > 2 * (context.canvas.width) / 5) {
            context.fillStyle = third[index];
        } else if (this.x > (context.canvas.width) / 5) {
            context.fillStyle = second[index];
        } else {
            context.fillStyle = first[index];
        }

    }
    update() {
        var dir = Math.PI * this.direction / 180;
        this.y += Math.sin(dir) * this.speed;       
        this.x += Math.cos(dir) * this.speed;
        this.fillStyle();
    }

    draw(context) {
        context.beginPath();
        this.fillStyle();
        context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
        context.fill();
    }

    setup() {
        this.x = Math.random() * canvas.width;
        this.y = Math.random() * canvas.height;
        this.speed = Math.random() * 1.5;
        this.direction = Math.random() * 360;
        this.radius = Math.random() * (canvas.width / canvas.height)*0.15; 
    }
}

function drawdotLines(net) {
    var copyNet = net.slice();
    while (copyNet.length > 0) {
        var dot = copyNet.pop();
        for (var n = 0; n < copyNet.length; n++) {
            var ndot = copyNet[n];
            var rx = Math.pow(dot.x - ndot.x, 2);
            var ry = Math.pow(dot.y - ndot.y, 2);
            var dist = Math.sqrt(rx + ry);
            if (dist < weight) {
                context.beginPath();
                index = parseInt(localStorage.getItem('index'));
                if (dot.x > 4 * (context.canvas.width) / 5) {
                    context.strokeStyle = fifth[index];
                } else if (dot.x > 3 * (context.canvas.width) / 5) {
                    context.strokeStyle = fourth[index];
                } else if (dot.x > 2 * (context.canvas.width) / 5) {
                    context.strokeStyle = third[index];
                } else if (dot.x > (context.canvas.width) / 5) {
                    context.strokeStyle = second[index];
                } else {
                    context.strokeStyle = first[index];
                }
                context.lineWidth = 2 * (weight - dist) / weight;
                context.moveTo(dot.x, dot.y);
                context.lineTo(ndot.x, ndot.y);
                context.stroke();
            }
        }
    }
}

function update() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    for (var i = 0; i < net.length; i++) {
        var dot = net[i];
        dot.update();
        dot.draw(context);
        if (dot.x < 0 || dot.x > canvas.width || dot.y < 0 || dot.y > canvas.height) {
            dot.setup();
        }
    }
    drawdotLines(net);
}

document.getElementsByClassName("color_change").onclick = function () {
    if (index == first.length - 1) {
        index = 0;
        toString(index);
        localStorage.setItem('index', index);
        update();
    } else {
        index++;
        localStorage.setItem('index', index);
        update();
    }
}

这就是我尝试创建画布的方式,它位于我的脚本文件的底部,我已经尝试了上面链接中给出的解决方案,但它根本不起作用。

for(var j=1;j<=nbCanvas;j++){
    let nd_canvas = document.getElementById("canvas#dot_"+j);
    window.setInterval(update.bind(this,canvas), 15); 
}

我期望的是这样的:http://jsfiddle.net/LIghningWolf/ygq2srj0/1 我制作了这个小提琴来显示结果,但我想要它用于我想要的尽可能多的画布。

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    最小的入侵可能是将画布像素复制到目标画布。

    由于update 绘制您的画布,我们可以假设每次更新后,都要复制画布:

    
        drawdotLines(net);
            [...document.querySelectorAll('.copy')].forEach(dst=>{
                dst.getContext('2d').clearRect(0,0,canvas.width, canvas.height);
                dst.getContext('2d').drawImage(canvas, 0, 0)
        })
    

    只需修改 css 以检查 copy-canvas 确实正确“复制”

    canvas{
    ...
        width:30%;
        border:1px solid black;
    }
    

    并且不要忘记将画布添加到 dom 中

           <canvas id="dot1"></canvas>
           <canvas class="copy"></canvas>
           <canvas class="copy"></canvas>
    

    作为侧节点,每次您update 时,您都会查询 DOM 以访问您的目标画布。最好将上下文作为参数传递给 update

    编辑:你的小提琴修改了http://jsfiddle.net/ndq6fa38/

    edit2:您可能想要使用requestAnimationFrame 而不是setInterval


    正如 LightninWolf 所说,目标是拥有单独的按钮。 那么这只是关于重构/封装。 将所有绘图代码包装在一个函数中并传递给它一个canvas

    function makeButton(canvas){
    ...
    
      function update() {...
    
      }
        return {update}
    }
    

    制作一些按钮

    let canvas = document.getElementsByTagName('canvas');
    let btns = [...canvas].map(canvas=>{
            return makeButton(canvas);
    })
    btns.forEach(btn=>{
        window.setInterval(btn.update.bind(btn), 15); 
    })
    

    按钮现在是独立的。

    注意:a onclick 事件也可以这样。 由于a 绑定到一个canvas,请考虑makeButton(canvas, a) 并处理每个btn 实例的点击

    编辑:fiddle

    【讨论】:

    • 非常感谢您快速而完整的回答,这几乎就是我想做的。我的问题是我真的不想复制第一个画布,我的锚标记充当按钮,我希望画布适合我的画布,每个锚都有自己的画布,所以当我将其悬停时动画从我悬停的按钮开始。对我来说仍然是一个很好的答案,我想我可以试试你给我的东西!
    • @LightninWolf 我有一个愚蠢的想法,我什至没有想到你想要不同的按钮。请参阅我的编辑帖子的第二部分
    • 好吧,除了你是我的英雄,我还能说什么,这正是我想要的。 “封装”技巧是我原始帖子链接中答案的一部分,但无论我尝试什么,我都无法根据需要进行设置,但你很容易做到。非常感谢您的帮助。
    猜你喜欢
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 2016-10-15
    • 2021-09-17
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多