按顺序在不同 xy 坐标的数组上绘制不同图像的数组

Draw an Array of different Images on an array of different xy-coordinates, in order

我有一个 canvas:

<canvas id="canvas" width="500px" height="500px"></canvas>

我从我页面上的复选框中提取了一组功能区图像:

<th><input value="0001" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0002" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0003" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0004" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0005" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>


let RibbonsArray = Array.from(document.getElementsByClassName("Ribbons"));
let CheckedRibbons = RibbonsArray.filter(element => element.checked == true);

我有几个 x/y 坐标数组:

var arr1 =[
[122, 235]
];
var arr2 =[
[69, 235],
[175, 235]
];
var arr3 =[
[16, 235],
[122, 235],
[228, 235]
];
var arr4 =[
[122, 220],
[16, 250],
[122, 250],
[228, 250]
];
var arr5 =[
[69, 220],
[175, 220],
[16, 250],
[122, 250],
[228, 250]
];

我有以下脚本:

function ClearLeft(){
    let clearLeft = canvas.height - 5;
    ctx.fillRect(2, 2, 345, clearLeft);
};

function ReDraw(){
    ClearLeft();
    //RIBBONS
    let CheckedRibbons = RibbonsArray.filter(element => element.checked == true);
        if (CheckedRibbons.length == arr1.length){
            CheckedRibbons.forEach(Ribbon => {
                let x = arr1[0][0];
                let y = arr1[0][1];
                let img = new Image();
                img.src = `Ribbons/${Ribbon.value}.png`
                img.addEventListener('load', () => {
                ctx.drawImage(img, x, y);
                });
            });
        } else if (CheckedRibbons.length == arr2.length){
        //When 2 Ribbons are checked -> Draw Ribbon 1 at arr2[0] which is [69, 235].
        //                           -> Draw Ribbon 2 at arr2[1] which is [175, 235].

        } else if (CheckedRibbons.length == arr3.length){
        //When 3 Ribbons are checked -> Draw Ribbon 1 at arr3[0] which is [16, 235].
        //                           -> Draw Ribbon 2 at arr3[1] which is [122, 235].
        //                           -> Draw Ribbon 3 at arr3[2] which is [228, 235].
        
        }
};//REDRAW ENDS

正如您在选择 2 或 3 个色带的情况下看到的那样,我正在尝试找出一种方法来绘制位于“CheckedRibbons”中的每个色带......按顺序......在每个长度匹配的数组的相应索引(这是一口,嗯,我希望我没有把它搞砸)。 我尝试过在不同的配置中嵌套“forEach”,我尝试使用索引。我只是无法解决这个问题。

如果稍微更改一下数据结构,有几种方法可以更轻松地完成此操作。好处是您的代码不需要更改或重复,它将全部依赖于数据更改,这在长期 运行.

中是一种更易于维护的方法

这里有两个不同的例子来说明我的意思,当然有很多方法来构建你的数据,这只是我选择的两种回答方式。每个示例下方的完整工作代码(我使用了测试图像)。

第一个例子使用了一个数组,数组...数组。不是代表数据的最清晰的选项只是因为你总是必须像这样访问 0 索引处的初始数据,

const renderGroups = [
  [
    [122, 235]
  ],
  [
    [69, 235],
    [175, 235]
  ],
  [
    [16, 235],
    [122, 235],
    [228, 235]
  ],
  [
    [122, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ],
  [
    [69, 220],
    [175, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ]
];

// access data group, since renderGroups is an array all data lives on the 0 index.
const renderGroup = renderGroups.filter(group => group.length === CheckedRibbons.length)[0]; 

为什么会这样的例子,当我们在 resultsGroup

中过滤寻找长度为 2 的数组时

renderGroups.filter(el => el.length === 2);

这就是 resultsGroup 的样子。

[
  [
    [69, 235],
    [175, 235]
  ]
]

这是由于 filter 返回一个数组,这意味着访问第一组,我们需要做 Array[0] 然后变成

  [
    [69, 235],
    [175, 235]
  ]

这给了我们我们期望的正常对。所以 Array[0] 例如是:

[69, 235]

这是另一个数组,所以我们需要做Array[0][0]得到69等。

let RibbonsArray = Array.from(document.getElementsByClassName("Ribbons"));
let CheckedRibbons = RibbonsArray.filter(element => element.checked == true);

const renderGroups = [
  [
    [122, 235]
  ],
  [
    [69, 235],
    [175, 235]
  ],
  [
    [16, 235],
    [122, 235],
    [228, 235]
  ],
  [
    [122, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ],
  [
    [69, 220],
    [175, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ]
];

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

function ClearLeft() {
  let clearLeft = canvas.height - 5;
  ctx.fillRect(2, 2, 345, clearLeft);
};

function ReDraw() {
  ClearLeft();
  //RIBBONS
  let CheckedRibbons = RibbonsArray.filter(element => element.checked == true);
  const renderGroup = renderGroups.filter(group => group.length === CheckedRibbons.length)[0];

  CheckedRibbons.forEach((Ribbon, idx) => {
    let x = renderGroup[idx][0];
    let y = renderGroup[idx][1];
    let img = new Image();
    img.src = 'https://i.picsum.photos/id/130/200/200.jpg?hmac=pMGv0FZ4yiuwOp40JbbSUg8DSKRdq2Rx70VXtqMrbjI';
    img.addEventListener('load', () => {
      ctx.drawImage(img, x, y);
    });
  });
}
// REDRAW ENDS
<canvas id="canvas" width="500px" height="500px"></canvas>
<th><input value="0001" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0002" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0003" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0004" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0005" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>

第二个选项是一个具有命名组属性的对象,它包含数组,但不是通用的,更易于管理和可读。缺点是访问 属性 依赖于精确的命名,如果您缺少预期的 属性 等,这可能会导致错误

const renderGroups = {
  group1: [
    [122, 235]
  ],
  group2: [
    [69, 235],
    [175, 235]
  ],
  group3: [
    [16, 235],
    [122, 235],
    [228, 235]
  ],
  group4: [
    [122, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ],
  group5: [
    [69, 220],
    [175, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ]
};

// access data group
const renderGroup = renderGroups[`group${CheckedRibbons.length}`];

let RibbonsArray = Array.from(document.getElementsByClassName("Ribbons"));
let CheckedRibbons = RibbonsArray.filter(element => element.checked == true);

const renderGroups = {
  group1: [
    [122, 235]
  ],
  group2: [
    [69, 235],
    [175, 235]
  ],
  group3: [
    [16, 235],
    [122, 235],
    [228, 235]
  ],
  group4: [
    [122, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ],
  group5: [
    [69, 220],
    [175, 220],
    [16, 250],
    [122, 250],
    [228, 250]
  ]
};

const CheckedRibbons = RibbonsArray.filter(element => element.checked == true);
const renderGroup = renderGroups[`group${CheckedRibbons.length}`];

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

function ClearLeft() {
  let clearLeft = canvas.height - 5;
  ctx.fillRect(2, 2, 345, clearLeft);
};

function ReDraw() {
  ClearLeft();
  //RIBBONS
  const CheckedRibbons = RibbonsArray.filter(element => element.checked == true);
  const renderGroup = renderGroups[`group${CheckedRibbons.length}`];

  console.log(renderGroup)

  CheckedRibbons.forEach((Ribbon, idx) => {
    let x = renderGroup[idx][0];
    let y = renderGroup[idx][1];
    let img = new Image();
    img.src = 'https://i.picsum.photos/id/130/200/200.jpg?hmac=pMGv0FZ4yiuwOp40JbbSUg8DSKRdq2Rx70VXtqMrbjI';
    img.addEventListener('load', () => {
      ctx.drawImage(img, x, y);
    });
  });
}
// REDRAW ENDS
<canvas id="canvas" width="500px" height="500px"></canvas>
<th><input value="0001" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0002" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0003" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0004" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>
<th><input value="0005" class="Ribbons" type="checkbox" onchange="ReDraw()"></th>