【发布时间】:2018-08-07 10:11:00
【问题描述】:
jsfiddle:https://jsfiddle.net/nragrkb8/3/
我正在尝试绘制频谱图,可以在 chrome 中使用,但在所有其他浏览器中都没有绘制任何内容。每次推入新数据时,我都使用 getImageData 和 putImageData 将现有内容向下移动一个像素。然后将新数据绘制到屏幕外图像中,然后 putimagedata 将其应用于整个画布。
Spectrogram = (function() {
//constructor function
var Spectrogram = function(options) {
//compose options
this.canvas = options.canvas;
this.width = options.size; //the size of the FFT
this.height = options.length; //the number of FFT to keep
if (typeof options.min !== 'undefined' && typeof options.max !== 'undefined') {
this.rangeType = 'static';
this.min = options.min;
this.max = options.max;
} else {
this.rangeType = 'auto';
this.min = Infinity;
this.max = -Infinity;
}
//set the function used to determine a value's color
this.colorScaleFn = options.colorScaleFn || defaultColorScaling;
//precalculate the range used in color scaling
this.range = this.max - this.min;
//the 2d drawing context
this.ctx = this.canvas.getContext('2d', { alpha: false });
//single pixel image used to draw new data points
this.im = this.ctx.createImageData(this.width, 1);
this.canvas.width = this.width;
this.canvas.height = this.height;
//adds a new row of data to the edge of the spectrogram, shifting existing
//contents by 1px
this.addData = function (newData) {
if (newData.length != this.width) {
console.error('Unmatched dataset size. Expected ' + this.width + ', was + ' + newData.length);
return;
}
if (this.rangeType == 'auto') {
var changed = false;
for (var i = 0; i < newData.length; ++i) {
if (newData[i] < this.min) {
this.min = newData[i];
changed = true;
} else if (newData[i] > this.max) {
this.max = newData[i];
changed = true;
}
}
if (changed) {
this.range = this.max - this.min;
}
}
//move the current contents by 1px
var im = this.ctx.getImageData(0, 0, this.width, this.height - 1);
this.ctx.putImageData(im, 0, 1);
//draw the new data values into the temporary image
var j = 0;
for (var i = 0; i < newData.length; ++i) {
var c = this.colorScaleFn(newData[i]);
this.im.data[j] = c[0];
this.im.data[j + 1] = c[1];
this.im.data[j + 2] = c[2];
j += 4;
}
//put the new data colors into the full canvas
this.ctx.putImageData(this.im, 0, 0);
}
}
function defaultColorScaling(value) {
var x = (value - this.min) / this.range;
if (x < 0) {
x = 0;
} else if (x > 1) {
x = 1;
}
var g = Math.pow(x, 2);
var b = 0.75 - 1.5 * Math.abs(x - 0.45);
var r = 0;
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
return Spectrogram;
})();
const size = 1024;
const length = 200;
const dataMax = 100;
const velMax = 1;
const canvas = document.getElementById('spec');
canvas.width = size;
canvas.height = length;
const spec = new Spectrogram({
canvas: canvas,
size: size,
length: length
});
const data = [];
const vel = [];
for (var i = 0; i < size; ++i) {
data.push(0);
vel.push(0);
}
setInterval(function() {
for (var i = 0; i < size; ++i) {
data[i] += vel[i];
if (i > 0) data[i] += vel[i - 1];
if (i < size - 1) data[i] += vel[i + 1];
if (data[i] >= dataMax) {
data[i] = dataMax;
vel[i] = 0;
} else if (data[i] <= -dataMax) {
data[i] = -dataMax;
vel[i] = 0;
}
if (vel[i] == 0) {
vel[i] = (Math.random() - 0.5) * 100;
}
}
spec.addData(data);
}, 100);
【问题讨论】:
-
我在 edge 或 firefox 的控制台中没有收到任何错误。
-
如果你想画一些东西,你需要将alpha通道设置为大于0。 jsfiddle.net/nragrkb8/10 另外,请注意,您应该不惜一切代价避免高频
setInterval执行可能需要超过间隔时间的任务(在您的情况下可以),而是使用类似 requestAnimtionFrame 循环的东西。不要使用 getImageData + putImageData 来更新您的上下文,只需使用ctx.drawImage(ctx.canvas, x, y)。您的代码中可能还有其他问题需要修复,但这里有一个 updated fiddle 包含这两个主要内容。 -
看来所有其他浏览器都忽略了 alpha: false 选项?
-
另外,您应该将其发布为答案,以便我接受!
-
alpha: false不应该关注 createImageData,这是 chrome 中的一个错误。我把这个问题更多地看作是一个typo,所以VTCed而不是回答它。但如果你不同意,我可以写一个。
标签: javascript canvas