语境:
我正在使用 Andrei Kashcha 的 (anvaka) panzoom 库:https ://github.com/anvaka/panzoom来提供详细的颜色选择功能:
我创建了一个 1' 电影来说明用例:https ://www.dropbox.com/s/5tv9rs18vvpv95d/tfs_cp.mov?dl=0
问题:
- 第 I 部分 [已解决,参见下文未解决的第 II 部分]
// 2020 年 14 月 12 日:初次发布
这一切在桌面上的 Chrome/Safari 上都可以正常工作,但是当切换到移动设备时,我在 touchend (_listener2) 上收到以下错误:
Uncaught ReferenceError: x is not defined
at cp_vfinal:1229
at useCanvas (cp_vfinal:761)
at HTMLImageElement._listener2 (cp_vfinal:1221)
更具体地说,我在下面分享的代码的以下部分:
var p = inst.canvas.getContext('2d')
.getImageData(x, y, 1, 1).data;
我的假设是这个错误也会出现在 touchmove (_listener4) 上,但我无法使用 Chrome 的内置移动设备模式正确测试它。我也无法访问 XCode,这也使得在 Safari 中进行测试也很困难。
// 29/12:更新
同时我发现以下代码导致了ReferenceError:
// chrome
if(e.offsetX) {
x = e.offsetX;
y = e.offsetY;
}
// firefox
else if(e.layerX) {
x = e.layerX;
y = e.layerY;
}
用以下替换它,解决了我的问题。
x = e.changedTouches[0].clientX - e.changedTouches[0].target.offsetLeft
y = e.changedTouches[0].clientY - e.changedTouches[0].target.offsetTop;
- 第二部分 [未解决]
// 2020 年 14 月 12 日:初次发布
在移动设备上缩放/平移并随后在移动设备上选择颜色时,似乎所做的颜色选择是基于尚未缩放/平移的画布。
我已经尝试了很多东西,但我根本无法弄清楚。尽管其他人也尝试过:
- 在 Canvas 上实现缩放
- 在移动设备上缩放画布
- 移动设备上糟糕的 Canvas GetImageData() / PutImageData() 性能
- Canvas getImageData 在某些移动设备上返回不正确的数据
我也无法使用该输入来解决我的问题。
// 29-12-2020: 更新
到今天为止,我仍然无法解决问题的第二部分。
比较时
console.log(inst.canvas);
console.log(inst.canvas.getContext('2d'))
对于移动设备和桌面设备,我没有看到任何区别,所以在移动设备上我无法通过 getImageData() 检索正确的数据,这真的很奇怪。如何确保 getImageData() 实际上检查缩放/缩放/平移图像(画布)而不是未缩放/未缩放/未平移图像(画布)?这已经可以帮助我进一步调试。
// 2021 年 5 月 4 日:更新
我还没有弄清楚是什么导致了这个问题。仍然存在三个关键问题:
- Q1:我使用 drawImage() 正确吗?
- Q2:我是否正确使用了 getImageData()?
- Q3:不管 Q1/Q2,为什么它在桌面上工作呢?
// 2021 年 5 月 15 日:更新
我还没有弄清楚是什么导致了这个问题。仍然存在相同的关键问题,但我在调查方面取得了一些进展:
- Q1:我使用 drawImage() 正确吗?
我现在尝试使用 void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); 而不是 void ctx.drawImage(image, dx, dy, dWidth, dHeight); 因为在阅读 MDN 上的文档后这似乎更合乎逻辑:https ://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage不幸的是,这并没有太大变化。我已经更新了下面的可视化以反映我的调整。
- Q2:我是否正确使用了 getImageData()?
我不知道这里可能有什么问题。
- Q3:不管 Q1/Q2,为什么它在桌面上工作呢?
我还在智能手机模拟器中测试了我的实现:https : //www.webmobilefirst.com/en/ 就像一个魅力。因此,实际上是导致问题的物理设备。
可视化:
内部尺寸为 2075x3112 的测试图像被加载到宽度 = 375 和高度 = 562 的画布中 - 这是左侧的情况。右侧的情况描述了平移/缩放后发生的情况。
片段:
- drawImage():平移/缩放时调用
function useCanvas(el, image, callback){
console.log("useCanvas")
console.log(image);
//https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage
//console.log(el.width);
//console.log(el.height);
if(!checkCanvasSize(el, image)){
console.log("checkCanvasSize")
el.width = image.width; // img width
el.height = image.height; // img height
console.log(el.width);
console.log(el.height);
// draw image in canvas tag - void ctx.drawImage(image, dx, dy, dWidth, dHeight);
el.getContext('2d').drawImage(image, 0, 0, image.width, image.height);
console.log(el)
console.log(el.getContext('2d'))
} else {
console.log("else ...")
console.log(image.style.transform)
//if no transformation - do nothing
//if transformation - do "something"
if(image.style.transform !== "matrix(1, 0, 0, 1, 0, 0)"){
//- draw transformed image onto canvas
el.getContext('2d').drawImage(image, 0, 0, image.width, image.height);
}
}
return callback();
}
- 获取图像数据()
_listener2 = function(e) { //touchend
//console.log(e.srcElement)
tlength = e.touches.length;
cpsig1 = cpsig1 + tlength.toString();
if(tlength === 0){
if( (tf.x < -1E-9 || tf.x > 1E-9) || (tf.y < -1E-9 || tf.y > 1E-9) || tf.scale > 1){ //pan or zoom is true
//activate CP again
activateCP = true;
//wait for the next user action to do something (e.g. click/tap)
if(cpsig1.slice(cpsig1.length - 2) === "00"){
registerC = true;
} else {
registerC = false;
}
} else {
//perform a check whether we came from a 'transformed' situation or not, in case yes, don't set the color.
if(transform === true){ //we came from a 'transformed' situation
registerC = false; //we wait for a user action
transform = false;
//tmpvar = true;
} else { //register the underlying color that was touched before going to TE=0 and move to next color (registerC should be true here)
//extra handle
if(cpsig1.slice(cpsig1.length - 2) === "20"){
registerC = false;
} else {
registerC = true;
}
}
}
}
// chrome
if(e.offsetX) {
x = e.offsetX;
y = e.offsetY;
}
// firefox
else if(e.layerX) {
x = e.layerX;
y = e.layerY;
}
useCanvas(inst.canvas, inst.img, function(){
// get image data
//console.log("Debug:")
//console.log(inst.img);
//console.log(inst.canvas);
//console.log(inst.canvas.getContext('2d'))
//https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas
var p = inst.canvas.getContext('2d')
.getImageData(x, y, 1, 1).data;
// show info
inst.result_hex = rgbToHex(p[0],p[1],p[2]);
inst.result_rgb_string = 'rgb('+p[0]+','+ p[1]+','+ p[2]+')';
// set value
console.log("skinSelection: ", skinSelection)
if(skinSelection === false && tlength === 0 && registerC === true){
document.getElementById("preview_skin").style.backgroundColor = rgbToHex(p[0],p[1],p[2]);
document.getElementById("preview_skin").style.backgroundSize = "42.5px 42.5px"
document.getElementById("preview_skin").style.backgroundImage = "url('https://static.wixstatic.com/media/3e929c_000c0389ad654985be5d7983694c7695~mv2.png')";
document.getElementById("preview_skin").style.backgroundRepeat = "no-repeat"
document.getElementById("preview_skin").style.backgroundPosition = "center 50%"
skinSelection = true;
document.getElementById('preview_skin').style.border = "5px solid #fff";
} else {
if(hairSelection === false && tlength === 0 && registerC === true){
document.getElementById("preview_hair").style.backgroundColor = rgbToHex(p[0],p[1],p[2]);
document.getElementById("preview_hair").style.backgroundSize = "42.5px 42.5px"
document.getElementById("preview_hair").style.backgroundImage = "url('https://static.wixstatic.com/media/3e929c_cad76816bc4441b6bfe34f5008b2741d~mv2.png')";
document.getElementById("preview_hair").style.backgroundRepeat = "no-repeat"
document.getElementById("preview_hair").style.backgroundPosition = "center 50%"
hairSelection = true;
document.getElementById('preview_hair').style.border = "5px solid #fff"
} else {
if(eyeSelection === false && tlength === 0 && registerC === true){
document.getElementById("preview_eye").style.backgroundColor = rgbToHex(p[0],p[1],p[2]);
document.getElementById("preview_eye").style.backgroundSize = "42.5px 42.5px"
document.getElementById("preview_eye").style.backgroundImage = "url('https://static.wixstatic.com/media/3e929c_f628dfa5fe0a412da6f06954a8657458~mv2.png')";
document.getElementById("preview_eye").style.backgroundRepeat = "no-repeat"
document.getElementById("preview_eye").style.backgroundPosition = "center 50%"
eyeSelection = true;
document.getElementById('preview_eye').style.border = "5px solid #fff"
}
}
}
console.log("R: " + p[0] + " - G: " + p[1] + " - B: " + p[2]);
});
}
'MWE':
由于很难为此创建 MWE,我将分享完整的工作示例,可在此处找到:https ://yvervoort.github.io/cp-acc_web_v0.2.html Javascript 可在“来源”下找到开发人员工具的选项卡。
变更日志:
- 2020 年 14 月 12 日:最初的问题
- 29-12-2020:更新问题 - 第一部分已解决 | 第二部分仍未解决
- 29-12-2020:更新标题以更好地反映尚待解决的问题
- 2021 年 5 月 4 日:更新了解释(包括问题的可视化)并添加了我认为与第二部分的问题有关的新关键问题,该问题仍未解决
- 15-05-2021:更新了我取得的进展,这是有限的。我现在确实知道该实现在智能手机模拟器上也可以正常工作,因此似乎只会在实际物理设备上引起问题。