可能在画布上通过引用变量来单击函数? [英] click functions through references variables on a canvas-possible?

查看:212
本文介绍了可能在画布上通过引用变量来单击函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用我目前的项目,只是遇到一点墙。所以对于我的音乐课程,我们必须创建一个24键(2倍频程)键盘,首先使用画布渲染键盘,然后使用网络音频加载和播放24种不同的声音。我已经得到我的剪辑成功加载到一个数组(或者所以我希望!),但有点困惑,我将如何处理点击事件和播放每个声音。在互联网周围搜索只产生了通过查找点击的坐标并通过该点击执行某个事件来处理点击事件的结果。这可能不适用于我的项目,因为我第一次渲染白键(其中14),然后渲染黑键的顶部(其中10)。这将使得通过坐标检测点击变得困难,因为白键不再是矩形。我的代码渲染键看起来像这样

  function createKeys(){
var r = document.getElementById钢琴');
var key = r.getContext('2d');
//创建白钢琴键
key.beginPath();
for(i = 0; i <14; i ++)
{
wKey = [key.rect(i * 70,0,70,120)];
key.fillStyle =#FFFFFF;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='black';
key.stroke();

}
key.closePath();

//开始黑键
key.beginPath();
var bKey1 = key.rect(53,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey2 = key.rect(123,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey3 = key.rect(263,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey4 = key.rect(333,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey5 = key.rect(403,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey6 = key.rect(543,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey7 = key.rect(613,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey8 = key.rect(753,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey9 = key.rect(823,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

var bKey10 = key.rect(893,0,35,80);
key.fillStyle =#000000;
key.fill();
key.lineWidth = 2;
key.strokeStyle ='#888888';
key.stroke();

key.closePath();
}



现在你可以看到我为白键创建了一个引用变量,数组称为wKey,索引为0到13(代表每个键),以及称为bKey1-10的黑键的各个变量,因为计算出这样一个模式的公式会煎炸我的大脑。我只是想知道我是否可以创建一个函数来检查这些引用是否被点击,而不是使用坐标跟踪来执行操作(如更改颜色和播放声音文件)在每个键。理想情况下,我想按照

 的方式做一些事情如果wKey [i] =点击
,那么
play soundfile [i]
else if bKey1 = clicked
播放声音文件[14]
else if bKey2 = clicked
播放声音文件[15]
...所以,

不确定这个的可行性,因为我从来没有弄乱画布,更不用说在画布上执行函数。



编辑:因为我创建了一个画布,我认为发布的HTML可能是有益的

 < body> 
< h1>< u> The Cory MatthewsUNDAPANTS钢琴< / u>作者:Chris C.< / h1>
< div id =controls_toolbar>



< / div>
< canvas id =pianowidth =980height =120style =border:1px solid#000000; class =centeronclick =keyClicked()> < / canvas>
< script>
const PATH ='/ mp3 /'
SOUNDS = ['DOWNUnderPantsC','DOWNUnderPantsD','DOWNUnderPantsE','DOWNUnderPantsF','DOWNUnderPantsG',
'DOWNUnderPantsA','DOWNUnderPantsB' ,'UPUnderPantsC','UPUnderPantsD','UPUnderPantsE','UPUnderPantsF',
'UPUnderPantsG','UPUnderPantsA','UPUnderPantsB','DOWNUnderPantsC#','DOWNUnderPantsD#','DOWNUnderPantsF#',
'DOWNUnderPantsG#','DOWNUnderPantsA#','UPUnderPantsC#','UPUnderPantsD#','UPUnderPantsF#','UPUnderPantsG#','UPUnderPantsA#']
createKeys
init();
fetchSounds();
< / script>
< p> Volume:< input type =rangemin =0max =100value =100oninput =VolumeSample.changeVolume />< / p>

< img class =centersrc =images / cm.pngalt =UNDAPANTSstyle =margin-top:20px>
< / body>


解决方案

基本上你必须实现一个手动按钮解决方案。这不是那么复杂,因为它听起来像(地图是btw。也是一种方式,但我不在这里覆盖)。



这个解决方案是动态的,这意味着你可以扩展八度音阶的数量,画布的大小等等。所有一切都会自动调整。



首先让notes数组定义每个八度音调中的键数,键应为黑色;我们将使用#附录确定:

  var notes = ['C','C#','D' ,'D#','E','F','F#','G','G#','A','A#','B' 
var keys = notes.length * octaves;

有关如何执行渲染的详细信息,请参阅下面的源代码。



使用单独的索引为白键循环通过键的数量(因为黑键相对于那些),我们得到一个完整的钢琴键盘。我们将键的计算x位置存储在两个不同的数组中,一个用于黑键,一个用于白键 - 这使得稍后进行命中测试变得更容易(替代方法是存储键形状 - 最大4 - 并将其用作命中测试路径)。



当钢琴被渲染时,我们可以检查鼠标按下事件(如果你想要在鼠标向下拖动时可以拖动来播放不同的键,一个down标志代替当鼠标下来,然后使用鼠标移动事件与一些优化 - 这里未显示此处的其余代码)。

  //检查鼠标位置
canvas.addEventListener('mousedown',function(e){

//调整鼠标位置
var rect = canvas.getBoundingClientRect (),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i,a;

// down
ctx.fillStyle ='#fa2';

// in blacks?
for(i = 0; a = arrayBlacks [i ++];){
ctx.beginPath(); // start new path for test
ctx.rect(a [0],0,blackKeyWidth - 2,h * .67); //添加一个矩形到路径
if(ctx.isPointInPath(x,y)){//测试点是否在路径
ctx.fill(); // yes,fill it
outputKey(a [1],a [2]); // show / play note
return;
}
}

//在白色? (与上面相同,但是对于arrayWhites)
for(i = 0; a = arrayWhites [i ++];){
... cut ...查看完整的源代码

},false);

当鼠标释放后,我们只是为了简单而重新渲染一切。对于较大的键盘(额外的八度),您可能需要考虑每个路径对象方法,其中每个键存储为形状。

  //如果鼠标向上,重新渲染所有
canvas.addEventListener('mouseup',function(e){
renderPiano(false);
},false);

所有详细信息都可以在附加的实时片段中找到。希望这有助于!



  //一些初始值/ setupvar canvas = document.getElementById('piano'),//获取画布ctx = canvas.getContext('2d'),//获取上下文h = canvas.height,//缓存维度w = canvas.width,octaves = 2,// octaves to render notes = ['C' C#','D','D#','E','F','F#','G','G#','A','A#','B'],keys = notes.length *八音度,//预计算的键数noteIndex = 0,//音符索引keyIndex = 0,//白键音符,// note whiteKeyWidth =(w /(7 * octaves))| 0,// width of whites blackKeyWidth = whiteKeyWidth * 0.75,//黑色的宽度i,//迭代器x,// x pos键arrayBlacks = [],//存储黑色位置arrayWhites = [] //存储白色位置; //计算钢琴键positionsfor(i = 0; i<键; i ++){noteIndex = i%notes.length; //在音符范围内强制note = notes [noteIndex]; // get note name x = keyIndex * whiteKeyWidth; // start pos。 of key if(note.length === 1){//白键(无锐)arrayWhites.push([x,note,i]); // store position keyIndex ++; // next white key index} else {x  -  = blackKeyWidth * .5; // adjust for black key arrayBlacks.push([x,note,i]); }} renderPiano(false); //基于whites / blacks数组的公共渲染函数//特殊开关:onlyBlacks覆盖掉色函数渲染的白色键renderPiano(onlyBlacks){var i,a; // render white keys if(!onlyBlacks){ctx.clearRect(0,0,w,h); // clear canvas for full render ctx.fillStyle ='#ffe'; for(i = 0; a = arrayWhites [i ++];){ctx.fillRect(a [0],0,whiteKeyWidth_2,h_1); ctx.strokeRect(a [0],0,whiteKeyWidth-2,h-1); }} // render black keys ctx.fillStyle ='#000'; for(i = 0; a = arrayBlacks [i ++];){ctx.fillRect(a [0],0,blackKeyWidth -2,h * .67); } //检查鼠标downcanvas.addEventListener('mousedown',function(e){//调整鼠标位置var rect = canvas.getBoundingClientRect(),x = e.clientX  -  rect.left,y = e.clientY  - rect.top,i,a; ctx.fillStyle ='#fa2'; // in blacks?for(i = 0; a = arrayBlacks [i ++];){ctx.beginPath(); ctx.rect ],0},0,blackKeyWidth  -  2,h * .67); if(ctx.isPointInPath(x,y)){ctx.fill(); outputKey(a [1],a [2]); return;}} / / in whites?for(i = 0; a = arrayWhites [i ++];){ctx.beginPath(); ctx.rect(a [0],0,whiteKeyWidth  -  2,h  -  1); if(ctx.isPointInPath (x,y)){ctx.fill(); renderPiano(true); //在顶部渲染黑色键!outputKey(a [1],a [2]); return;}}},false)如果鼠标向上,重新渲染allcanvas.addEventListener('mouseup',function(e){renderPiano(false);},false); //格式输出这里,播放正确的音符等功能outputKey(key,index){out.innerHTML = key +((index / 12)| 0); // play note}  

 < canvas id =piano width = 540 height = 160>< / canvas>< br>< output id =out>< / output>  


Just run into a bit of wall with my current project. So for my comp musics course we have to create a 24 key (2 octave) keyboard by first rendering a keyboard using a canvas and then using web audio to loading and play 24 different sounds. I have gotten my clips successfully loaded into an array(or so I hope!) but am a bit confused as to how I would go about handling click events and playing each sound. Searching around the internet has only yielded results about handling click events through finding the coordinates of the click and performing a certain event through that. That may not work for my project as I first render the white keys (14 of them) and then rendering the black keys on top (10 of those). That would make it difficult to detect clicks via coordinates as the white keys are no longer rectangle. My code for rendering the keys looks as such

function createKeys() {
var r = document.getElementById('piano');
var key = r.getContext('2d');
// creates white piano keys
key.beginPath();
for (i = 0; i < 14; i++)
{
wKey = [key.rect(i*70, 0, 70, 120)];
key.fillStyle = "#FFFFFF";
key.fill();
key.lineWidth = 2;
key.strokeStyle = 'black';
key.stroke();

}
key.closePath();

// begin black keys 
key.beginPath();
var bKey1 = key.rect(53, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey2 = key.rect(123, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey3 = key.rect(263, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey4 = key.rect(333, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey5 = key.rect(403, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey6 = key.rect(543, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey7 = key.rect(613, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey8 = key.rect(753, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey9 = key.rect(823, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

var bKey10 = key.rect(893, 0, 35, 80);
key.fillStyle = "#000000";
key.fill();
key.lineWidth= 2;
key.strokeStyle = '#888888';
key.stroke();

key.closePath();
}

Now as you can see I created a reference variable for the white keys, an array called 'wKey' with indices 0 through 13(to represent each key), and individual variables for black keys called bKey1-10, because figuring out a formula to such a pattern was frying my brain. I was just wondering if I could create a function to check if those references were clicked instead of using coordinate tracking to perform actions (such as changing the color and playing the soundfile) on each key. Ideally I would like to do something along the lines of

 If wKey[i] = clicked
 then
 play soundfile[i]
 else if bKey1 = clicked
 play soundfile[14]
 else if bKey2 = clicked
 play soundfile[15]
 ... and so on

Not sure of the feasibility of this as I've never had to mess around with a canvas, let alone performing functions on a canvas. Would like to hear what some fresh minds have to say about this.

EDIT: Since I'm creating a canvas I figured posting the HTML might be beneficial

<body>
    <h1><u>The Cory Matthews "UNDAPANTS" Piano</u> by Chris C.</h1>
    <div id = "controls_toolbar">



    </div>
    <canvas id="piano" width = "980" height = "120" style ="border:1px solid #000000;" class="center" onclick ="keyClicked()"> </canvas>
        <script>
            const PATH = '/mp3/'
                  SOUNDS = ['DOWNUnderPantsC', 'DOWNUnderPantsD', 'DOWNUnderPantsE', 'DOWNUnderPantsF', 'DOWNUnderPantsG',
                  'DOWNUnderPantsA', 'DOWNUnderPantsB', 'UPUnderPantsC', 'UPUnderPantsD', 'UPUnderPantsE', 'UPUnderPantsF',
              'UPUnderPantsG', 'UPUnderPantsA', 'UPUnderPantsB', 'DOWNUnderPantsC#', 'DOWNUnderPantsD#', 'DOWNUnderPantsF#',
          'DOWNUnderPantsG#', 'DOWNUnderPantsA#', 'UPUnderPantsC#', 'UPUnderPantsD#', 'UPUnderPantsF#', 'UPUnderPantsG#', 'UPUnderPantsA#']
            createKeys();
            init();
            fetchSounds();
        </script>
    <p>Volume: <input type="range" min="0" max="100" value="100" oninput="VolumeSample.changeVolume(this);" /></p>

    <img class="center" src="images/cm.png" alt="UNDAPANTS" style="margin-top: 20px">
</body>

解决方案

Basically you have to implement a manual button solution for canvas. This is not so complicated as it sounds as (a map is btw. also a way but I'm not covering it here).

This solution is dynamic which means you can expand the number of octaves, size of canvas etc. all everything will adjust automatically.

First let the notes array defined the number of keys in each octave as well as which keys should be black; we'll use the # appendix to determine that:

var notes = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
var keys = notes.length * octaves;

Please refer to the source below on how the render is performed in detail.

Looping through the number of keys using a separate index for white keys (as the black keys are relative to those) we get a full piano keyboard. We store the calculated x positions of the keys in two different arrays, one for black keys and one for whites - this makes it easier to do hit tests later (alternative is to store key shapes - max 4 - and use those as hit test paths).

When the piano is rendered we can check for mouse down events (if you want to be able to drag when mouse is down to play different keys you need to set a down flag instead when mouse is down and then use the rest of the code inside a mouse move events with some optimizations - not shown here).

// check for mouse down
canvas.addEventListener('mousedown', function(e) {

    // adjust mouse position
    var rect = canvas.getBoundingClientRect(),
        x = e.clientX - rect.left,
        y = e.clientY - rect.top,
        i, a;

    // fill color for key down
    ctx.fillStyle = '#fa2';

    //in blacks?
    for(i = 0; a = arrayBlacks[i++];) {
        ctx.beginPath();                               // start new path for test
        ctx.rect(a[0], 0, blackKeyWidth - 2, h * .67); // add a rect to path
        if (ctx.isPointInPath(x, y)) {                 // test if point is in path
            ctx.fill();                                // yes, fill it
            outputKey(a[1], a[2]);                     // show/play note
            return;
        }
    }

    //in whites? (same as above, but for arrayWhites)
    for(i = 0; a = arrayWhites[i++];) {
    ...cut... see full source

}, false);

When mouse is released we just re-render everything for simplicity. For larger keyboards (additional octaves) you might want to consider a per-path object approach where each key is stored as shape.

// if mouse up, re-render all
canvas.addEventListener('mouseup', function(e) {
    renderPiano(false);
}, false);

All details can be found in the attached live snippet. Hope this helps!

// some initial values/setup
var canvas = document.getElementById('piano'),  // get canvas
    ctx = canvas.getContext('2d'),              // get context
    h = canvas.height,                          // cache dimension
    w = canvas.width,
    
    octaves = 2,                                // octaves to render
    notes = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'],
    keys = notes.length * octaves,              // pre-calc num of keys
    noteIndex = 0,                              // note index
    keyIndex = 0,                               // white key index
    note,                                       // note
    whiteKeyWidth = (w / (7 * octaves))|0,      // width of whites
    blackKeyWidth = whiteKeyWidth * 0.75,       // width of blacks
    i,                                          // iterator
    x,                                          // x pos of key
    
    arrayBlacks = [],                           // store black positions
    arrayWhites = []                            // store white positions
;

// calc piano key positions

for (i = 0; i < keys; i++) {

    noteIndex = i % notes.length;               // force within notes range
    note = notes[noteIndex];                    // get note name
    x = keyIndex * whiteKeyWidth;               // start pos. of key
    
    if (note.length === 1) {                    // white key (no sharp)
        arrayWhites.push([x, note, i]);         // store position
        keyIndex++;                             // next white key index
    }
    else {
        x -= blackKeyWidth * .5;                // adjust for black key
        arrayBlacks.push([x, note, i]);
    }
}

renderPiano(false);

// common render function based on whites/blacks arrays
// special switch: onlyBlacks to override white key rendered while down
function renderPiano(onlyBlacks) {

    var i, a;
    
    //render white keys
    if (!onlyBlacks) {
        ctx.clearRect(0, 0, w, h); // clear canvas for full render
        ctx.fillStyle = '#ffe';
        for(i = 0; a = arrayWhites[i++];) {
            ctx.fillRect(a[0], 0, whiteKeyWidth - 2, h - 1);
            ctx.strokeRect(a[0], 0, whiteKeyWidth - 2, h - 1);
        }
    }
  
    //render black keys
    ctx.fillStyle = '#000';
    for(i = 0; a = arrayBlacks[i++];) {
        ctx.fillRect(a[0], 0, blackKeyWidth - 2, h * .67);
    }
}

// check for mouse down
canvas.addEventListener('mousedown', function(e) {

    // adjust mouse position
    var rect = canvas.getBoundingClientRect(),
        x = e.clientX - rect.left,
        y = e.clientY - rect.top,
        i, a;

    ctx.fillStyle = '#fa2';

    //in blacks?
    for(i = 0; a = arrayBlacks[i++];) {
        ctx.beginPath();
        ctx.rect(a[0], 0, blackKeyWidth - 2, h * .67);
        if (ctx.isPointInPath(x, y)) {
            ctx.fill();
            outputKey(a[1], a[2]);
            return;
        }
    }

    //in whites?
    for(i = 0; a = arrayWhites[i++];) {
        ctx.beginPath();
        ctx.rect(a[0], 0, whiteKeyWidth - 2, h - 1);
        if (ctx.isPointInPath(x, y)) {
            ctx.fill();
            renderPiano(true);     // render black keys on top!
            outputKey(a[1], a[2]);
            return;
        }
    }

}, false);

// if mouse up, re-render all
canvas.addEventListener('mouseup', function(e) {
    renderPiano(false);
}, false);

// format output here, ie. play correct note etc.
function outputKey(key, index) {
    out.innerHTML = key + ((index / 12)|0);
    // play note
}

<canvas id="piano" width=540 height=160></canvas>
<br><output id="out"></output>

这篇关于可能在画布上通过引用变量来单击函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆