可以通过画布上的引用变量来单击函数
click functions through references variables on a canvas-possible?
我当前的项目遇到了一些麻烦。因此,对于我的comp音乐课程,我们必须创建一个24键(2倍频程)键盘,首先使用画布渲染键盘,然后使用网络音频加载和播放24种不同的声音。我已经成功地将我的剪辑加载到了一个数组中(或者我希望如此!),但对于如何处理点击事件和播放每个声音,我有点困惑。在互联网上搜索只能通过找到点击的坐标并通过它执行某个事件来处理点击事件。这可能不适用于我的项目,因为我首先渲染白键(其中14个),然后在顶部渲染黑键(其中10个)。这将使通过坐标检测点击变得困难,因为白键不再是矩形。我渲染密钥的代码看起来像
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();
}
现在,正如你所看到的,我为白键创建了一个参考变量,一个名为"wKey"的数组,索引为0到13(表示每个键),为黑键创建了单独的变量bKey1-10,因为找出这样一个模式的公式让我的大脑炸开了锅。我只是想知道我是否可以创建一个函数来检查这些引用是否被点击,而不是使用坐标跟踪来对每个键执行操作(如更改颜色和播放声音文件)。理想情况下,我想做一些类似的事情
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
我不确定这是否可行,因为我从来没有在画布上乱搞过,更不用说在画布上执行功能了。我想听听一些新鲜人对此有什么看法。
编辑:由于我正在创建一个画布,我认为发布HTML可能是有益的
<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>
基本上,您必须为画布实现手动按钮解决方案。这并不像听起来那么复杂(顺便说一句,地图也是一种方式,但我不在这里介绍它)。
这个解决方案是动态的,这意味着你可以扩展八度音阶的数量、画布的大小等。所有的东西都会自动调整。
首先,让音符数组定义每个八度音阶中的键数,以及哪些键应该是黑色的;我们将使用#附录来确定:
var notes = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
var keys = notes.length * octaves;
有关渲染的详细执行方式,请参阅以下来源。
使用白键的单独索引循环键的数量(因为黑键是相对的),我们得到了一个完整的钢琴键盘。我们将计算出的键的x位置存储在两个不同的数组中,一个用于黑键,另一个用于白键,这使得以后更容易进行命中测试(另一种选择是存储键形状-最多4个-并将其用作命中测试路径)。
当钢琴被渲染时,我们可以检查鼠标按下事件(如果你想在鼠标按下时拖动以播放不同的键,你需要在鼠标按下的时候设置一个向下标志,然后在鼠标移动事件中使用其他代码并进行一些优化-这里没有显示)。
// 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);
当鼠标释放时,为了简单起见,我们只是重新渲染所有内容。对于较大的键盘(额外的八度音阶),您可能需要考虑按路径对象方法,其中每个键都存储为形状。
// if mouse up, re-render all
canvas.addEventListener('mouseup', function(e) {
renderPiano(false);
}, false);
所有详细信息都可以在所附的实时片段中找到。希望这能有所帮助!
// 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>
- 若单击按钮,则更改Javascript中的变量
- 单击“JavaScript显示变量”
- 单击按钮时填充javascript变量
- Angularjs - url params:单击时返回 url 中的角度变量
- 如何使按钮图像在单击时添加到变量中
- 未捕获的引用错误:变量未在单击函数上定义
- 如何在单击链接后将局部变量发送到部分呈现
- 如何将变量从按钮的单击传递给 javascript 代码
- 如何在用户单击提交按钮时为变量分配任意值
- 如何在jQuery中单击时重新计算变量
- 在ng中指定变量,重复ng次单击
- JavaScript变量在第二次单击事件时间后取消设置
- 将变量推送到数组中,并在每次单击时更新数组
- casperjs单击的不是选择器,而是变量
- 在单击 jQuery 事件中找不到变量
- d3.js onclick事件在单击时使用变量的值,而不是在绘制时
- 在浏览器返回/forwd 按钮单击时保存/恢复所有 JavaScript 变量
- jquery使用单击函数增加PHP变量
- 添加 JavaScript 变量以单击以调用链接
- 使用变量单击表行