我正在实施一个工作正常的webgl放大镜。
但是当我使用鼠标滚轮应用变焦时,它会扭曲。
我正在使用fabric.js并且fcanvas.getZoom()
返回我用来缩放放大镜的当前缩放级别。
这里是codepen。 任何人都可以检查为什么它在使用鼠标滚轮放大时不起作用。
代码:
`
MainCanvas = (function() {
function MainCanvas(image, WIDTH, HEIGHT) {
var err;
this.image = image;
this.WIDTH = WIDTH != null ? WIDTH : 128;
this.HEIGHT = HEIGHT != null ? HEIGHT : 128;
this.mouseout = bind(this.mouseout, this);
this.mouseover = bind(this.mouseover, this);
this.mousemove = bind(this.mousemove, this);
this.render = bind(this.render, this);
zoomcanvas = $(document.createElement('canvas'));
zoomcanvas.css({
'position': 'absolute',
'width': this.WIDTH,
'height': this.HEIGHT,
'z-index': '1000',
'border': '3px solid rgba(0,0,0,0.4)',
'border-radius': '50%',
'box-shadow': '2px 2px 16px 2px #223',
'pointer-events': 'none'
});
$('#canvases').append(zoomcanvas);
med = [0.5, 0.5];
this.scaled = 1;
try {
this.gl = zoomcanvas[0].getContext("experimental-webgl") || zoomcanvas[0].getContext("webgl");
} catch (_error) {
err = _error;
console.log(err.message);
alert(err.message);
}
this.gl.clearColor(0.8, 0.8, 0.8, 1.0);
this.mouse = {
x: .5,
y: .5
};
this.mvMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
this.pMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
this.data = {};
this.initShaders();
this.initBuffers();
this.initImages();
this.render();
this.image.mousemove(this.mousemove);
this.image.mouseover(this.mouseover).mouseout(this.mouseout);
}
MainCanvas.prototype.initShaders = function() {
var fragmentShader, vertexShader;
fragmentShader = this.getShader('shader-fs');
vertexShader = this.getShader('shader-vs');
this.shaderProgram = this.gl.createProgram();
this.gl.attachShader(this.shaderProgram, vertexShader);
this.gl.attachShader(this.shaderProgram, fragmentShader);
this.gl.linkProgram(this.shaderProgram);
if (!this.gl.getProgramParameter(this.shaderProgram, this.gl.LINK_STATUS)) {
console.log('Não pode inicializar shaders!');
}
this.gl.useProgram(this.shaderProgram);
this.data.vertexPositionAttribute = this.gl.getAttribLocation(this.shaderProgram, "aVertexPosition");
this.gl.enableVertexAttribArray(this.data.vertexPositionAttribute);
this.data.textureCoordAttribute = this.gl.getAttribLocation(this.shaderProgram, "aTextureCoord");
this.gl.enableVertexAttribArray(this.data.textureCoordAttribute);
this.data.samplerUniform0 = this.gl.getUniformLocation(this.shaderProgram, "sampler0");
this.data.medUniform = this.gl.getUniformLocation(this.shaderProgram, "med");
this.data.scaledUniform = this.gl.getUniformLocation(this.shaderProgram, "scaled");
};
MainCanvas.prototype.setMatrixUniforms = function() {
var normalMatrix;
this.gl.uniformMatrix4fv(this.data.pMatrixUniform, false, this.pMatrix);
this.gl.uniformMatrix4fv(this.data.mvMatrixUniform, false, this.mvMatrix);
normalMatrix = [1, 0, 0, 0, 1, 0, 0, 0, 1];
return this.gl.uniformMatrix3fv(this.data.nMatrixUniform, false, normalMatrix);
};
MainCanvas.prototype.getShader = function(id) {
var k, shader, shaderScript, str;
shaderScript = document.getElementById(id);
if (shaderScript === null) {
return false;
}
str = '';
k = shaderScript.firstChild;
while (k) {
if (k.nodeType === 3) {
str += k.textContent;
}
k = k.nextSibling;
}
if (shaderScript.type === "x-shader/x-fragment") {
shader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
} else {
shader = this.gl.createShader(this.gl.VERTEX_SHADER);
}
this.gl.shaderSource(shader, str);
this.gl.compileShader(shader);
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
console.log(this.gl.getShaderInfoLog(shader));
return false;
}
return shader;
};
MainCanvas.prototype.initBuffers = function() {
return this.bufferPlane();
};
MainCanvas.prototype.bufferPlane = function() {
var buffer, colors, indices, normais, uv, vertices;
vertices = [-1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0];
buffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(vertices), this.gl.STATIC_DRAW);
buffer.itemSize = 3;
buffer.numItems = 4;
this.data.vertexPositionBuffer = buffer;
normais = [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1];
buffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(normais), this.gl.STATIC_DRAW);
buffer.itemSize = 4;
buffer.numItems = 4;
this.data.vertexColorBuffer = buffer;
uv = [0, 0, 1, 0, 0, 1, 1, 1];
buffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(uv), this.gl.STATIC_DRAW);
buffer.itemSize = 2;
buffer.numItems = 4;
this.data.vertexTextureCoordBuffer = buffer;
indices = [0, 1, 2, 2, 3, 1];
buffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, buffer);
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), this.gl.STATIC_DRAW);
buffer.itemSize = 1;
buffer.numItems = 6;
return this.data.vertexIndexBuffer = buffer;
};
MainCanvas.prototype.handleTexture = function(texture) {
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, canvas);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
this.gl.bindTexture(this.gl.TEXTURE_2D, null);
this.scaled = Math.max(this.WIDTH / this.image.width(), this.HEIGHT / this.image.height());
return this.scaled / (fcanvas.getZoom());
};
MainCanvas.prototype.initImages = function() {
this.data.texture0 = this.gl.createTexture();
this.handleTexture(this.data.texture0);
};
MainCanvas.prototype.render = function(t) {
this.gl.viewport(0, 0, zoomcanvas[0].width, zoomcanvas[0].height);
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
this.gl.uniform1f(this.data.scaledUniform, this.scaled / fcanvas.getZoom() / 2);
this.gl.uniform2f(this.data.medUniform, parseFloat(med[0]) , parseFloat(med[1]));
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.data.vertexPositionBuffer);
this.gl.vertexAttribPointer(this.data.vertexPositionAttribute, this.data.vertexPositionBuffer.itemSize, this.gl.FLOAT, false, 0, 0);
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.data.vertexTextureCoordBuffer);
this.gl.vertexAttribPointer(this.data.textureCoordAttribute, this.data.vertexTextureCoordBuffer.itemSize, this.gl.FLOAT, false, 0, 0);
this.gl.activeTexture(this.gl.TEXTURE0);
this.gl.bindTexture(this.gl.TEXTURE_2D, this.data.texture0);
this.gl.uniform1i(this.data.samplerUniform0, 0);
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.data.vertexIndexBuffer);
this.setMatrixUniforms();
return this.gl.drawElements(this.gl.TRIANGLES, this.data.vertexIndexBuffer.numItems, this.gl.UNSIGNED_SHORT, 0);
};
MainCanvas.prototype.mousemove = function(e) {
var o2, x, y;
o2 = this.image.offset();
x = (e.offsetX + o2.left);
y = (e.offsetY + o2.top);
zoomcanvas.css({
'left': parseInt(x - this.WIDTH * 0.5),
'top': parseInt(y - this.HEIGHT * 0.5)
});
med[0] = (((e.offsetX - imageAttrs.left) ) / (oImg.width));
med[1] = (1.0 - (((e.offsetY - imageAttrs.top)) / (oImg.height)));
$('body').css('cursor', 'none');
return this.render();
};
MainCanvas.prototype.mouseover = function(e) {
return zoomcanvas.show();
};
MainCanvas.prototype.mouseout = function(e) {
return zoomcanvas.fadeOut("fast");
};
return MainCanvas;
})();
window.requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
return window.setTimeout(callback, 40);
};
window.onload = function(e) {
var mainCanvas;
console.clear();
console.log(Date.now());
var width = $("#sampler0")[0].width; var height = $("#sampler0")[0].height;
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
var AR = calculateAspectRatio(width, height);
ctx.drawImage($("#sampler0")[0], 0, 0, AR.renderableWidth, AR.renderableHeight);
var scaleX = AR.renderableWidth / width;
var scaleY = AR.renderableHeight / height;
oImg = new fabric.Image(canvas,
{
selectable : false,
width : width,
height : height,
lockUniScaling: true,
centeredScaling: true,
scaleX : scaleX,
scaleY : scaleY,
alignX : "mid",
alignY : "mid",
});
fcanvas.add(oImg);
///bring image to center
fcanvas.centerObject(oImg);
/////////////////////////////////////////////////////////
///scale image back to default
oImg.scaleX = 1;
oImg.scaleY = 1;
///get left and top for zooming correctly.
imageAttrs.scaleX = scaleX;
fcanvas.zoomToPoint({ x: oImg.left, y: oImg.top }, scaleX);
oImg.on('mouseout', function(event) {
zoomcanvas.fadeOut("fast");
});
oImg.on('mouseover', function(event) {
zoomcanvas.show();
});
imageAttrs.left = oImg.left;
imageAttrs.top = oImg.top;
fcanvas.renderAll();
applyZoom();
return mainCanvas = new MainCanvas($("#canvases"), 256, 256);
};
var calculateAspectRatio = function (width, height) {
var imageAspectRatio = width / height;
var canvasAspectRatio = windowWidth / windowHeight;
var renderableHeight, renderableWidth, xStart, yStart;
var AR = new Object();
/// If image's aspect ratio is less than canvas's we fit on height
/// and place the image centrally along width
if(imageAspectRatio < canvasAspectRatio) {
renderableHeight = windowHeight ;
renderableWidth = width * (renderableHeight / height);
xStart = (windowWidth - renderableWidth) / 2;
yStart = 0;
}
/// If image's aspect ratio is greater than canvas's we fit on width
/// and place the image centrally along height
else if(imageAspectRatio > canvasAspectRatio) {
renderableWidth = $(window).width()
renderableHeight = height * (renderableWidth / width);
xStart = 0;
yStart = ( windowHeight - renderableHeight) / 2;
}
///keep aspect ratio
else {
renderableHeight = windowHeight ;
renderableWidth = windowWidth;
xStart = 0;
yStart = 0;
}
AR.renderableHeight = renderableHeight;
AR.renderableWidth = renderableWidth;
return AR;
}
/**
* Used to apply Zooming on the canvas.
*/
var applyZoom = function () {
var canvasarea = document.getElementById("canvases");
if (canvasarea.addEventListener) {
// IE9, Chrome, Safari, Opera
canvasarea.addEventListener("mousewheel", zoom, false);
// Firefox
canvasarea.addEventListener("DOMMouseScroll", zoom, false);
}
// IE 6/7/8
else canvasarea.attachEvent("onmousewheel", zoom);
return this;
}
function zoom(e) {
var evt=window.event || e;
var delta = evt.detail? evt.detail*(-120) : evt.wheelDelta;
var curZoom = fcanvas.getZoom(), newZoom = curZoom + delta / 4000,
x = e.offsetX, y = e.offsetY;
//applying zoom values.
fcanvas.zoomToPoint({ x: x, y: y }, newZoom);
if(e != null)e.preventDefault();
return false;
}
}).call(this);`
由于