计算机图形学Web前端笔记-图形平移放缩原理及实现(two.js鼠标事件适用所有渲染)
在two.js中,只提供了svg渲染時的鼠標事件,而canvas和webgl并沒有提供,這樣就對本人造成了很大的困擾,因此學習了下計算機圖形學相關的知識,實現了利用two.js繪圖在canvas、svg、webgl渲染方式下,放縮或移動場景,還能使用鼠標對其進行點擊交互。
?
下面先演示下截圖:
點擊綠色的矩形:
從上面的圖可以看出變色了。
下面滾動滾輪及拖動下場景:
同樣點擊剛剛那個矩形:
還是可以被找到,并且改變顏色。
?
下面先來說下2d圖形中平移和放縮的原理(非常重要,下面的代碼實現都需要用到):
平移:
放縮:
放縮+平移:
可見是先放縮,然后再進行平移。
總結下:
a b c d e f g h i其中a為:水平放縮;
其中c為:水平位移;
其中e為:垂直放縮;
其中f為:垂直位移。
?
下面來看下代碼是如何實現的:
在two.js,two對象:
在scene中存在_matrix里面存儲了Float32Array(9),這里就對應了上面的3*3矩陣,上面的就是單位矩陣,
1 0 0 0 1 0 0 0 1?
當放縮或移動后:
創建這幾個矩形的代碼:
代碼如下:
function createBtn(id, x, y, weight, color) {rect = two.makeRectangle(x, y, 200, 200);rect.noStroke();rect.fill = color;rect.myId = id;map.set(rect, weight); } 這些rect都存儲在map中,如何在: $stage.bind('mousedown', function(event){isPressed = true;originalPositionX = event.clientX;originalPositionY = event.clientY;let x = event.clientX;let y = event.clientY;let letX = (rect._translation._x / 2 * (two.scene._matrix.elements[0]) + two.scene._matrix.elements[2]);let letY = (rect._translation._y / 2 * (two.scene._matrix.elements[4]) + two.scene._matrix.elements[5]);let letWidth = rect._width * two.scene._matrix.elements[0];let letHeight = rect._height *two.scene._matrix.elements[4];// if(x > letX &&// y > letY &&// x < letX + letWidth &&// y < letY + letHeight// ){//// console.log("find it");// }// console.log("坐標 x=" + x + " y=" + y);console.log(two);for(let value of map){let xOffset = value[0]._width / 2;let yOffset = value[0]._height / 2;// console.log("xOffset:" + xOffset);// console.log("yOffset:" + yOffset);// console.log(value[0])let letX = ((value[0]._translation._x - xOffset) * (two.scene._matrix.elements[0]) + two.scene._matrix.elements[2]);let letY = ((value[0]._translation._y - yOffset) * (two.scene._matrix.elements[4]) + two.scene._matrix.elements[5]);let letWidth = value[0]._width * two.scene._matrix.elements[0];let letHeight = value[0]._height * two.scene._matrix.elements[4];// console.log("id:" + value[0].myId);// console.log("letX:" + letX + " letY:" + letY);// console.log("letWidth: " + letWidth + " letHeight:" + letHeight);// console.log("");if(x > letX &&y > letY &&x < letX + letWidth &&y < letY + letHeight){let r = Math.round(Math.random() * 255);let g = Math.round(Math.random() * 255);let b = Math.round(Math.random() * 255);let rgbStr = "rgb(" + r + "," + g + "," + b + ")";value[0].fill = rgbStr;console.log("find it " + value[0].myId);break;}}// console.log("---------------------------------");});代碼按下時對map進行遍歷,如何將其進行轉換后的坐標以及寬度進行矩陣變化即可:
這里有一點要說明的two.js中畫矩形如果是從200,?200開始,那么這個200,200將會是矩形的
中心點,并不是左上角的點,所以這里有功offset.
?
鼠標拖動,滾輪放縮相關的代碼:
(function(Two){let _ = Two.Utils;let Surface = function(object) {this.object = object;};_.extend(Surface.prototype, {limits: function(min, max) {let min_exists = !_.isUndefined(min);let max_exists = !_.isUndefined(max);if (!max_exists && !min_exists) {return { min: this.min, max: this.max };}this.min = min_exists ? min : this.min;this.max = max_exists ? max : this.max;return this;},apply: function(px, py, s) {this.object.translation.set(px, py);this.object.scale = s;return this;}});let ZUI = Two.ZUI = function(group, domElement) {this.limits = {scale: ZUI.Limit.clone(),x: ZUI.Limit.clone(),y: ZUI.Limit.clone()};this.viewport = domElement || document.body;this.viewportOffset = {matrix: new Two.Matrix()};this.surfaceMatrix = new Two.Matrix();this.surfaces = [];this.reset();this.updateSurface();this.add(new Surface(group));};_.extend(ZUI, {Surface: Surface,Clamp: function(v, min, max) {return Math.min(Math.max(v, min), max);},Limit: {min: -Infinity,max: Infinity,clone: function() {let result = {};for (let k in this) {result[k] = this[k];}return result;}},TranslateMatrix: function(m, x, y) {m.elements[2] += x;m.elements[5] += y;return m;},PositionToScale: function(pos){return Math.exp(pos);},ScaleToPosition: function(scale){return Math.log(scale);}});_.extend(ZUI.prototype, {constructor: ZUI,add: function(surface){this.surfaces.push(surface);let limits = surface.limits();this.addLimits(limits.min, limits.max);return this;},addLimits: function(min, max, type) {type = type || 'scale';if (!_.isUndefined(min)){if(this.limits[type].min){this.limits[type].min = Math.max(min, this.limits[type].min);}else{this.limits[type].min = min;}}if(_.isUndefined(max)){return this;}if(this.limits[type].max){this.limits[type].max = Math.min(max, this.limits[type].max);}else{this.limits[type].max = max;}return this;},clientToSurface: function(x, y) {this.updateOffset();let m = this.surfaceMatrix.inverse();let n = this.viewportOffset.matrix.inverse().multiply(x, y, 1);return m.multiply.apply(m, _.toArray(n));},surfaceToClient: function(v) {this.updateOffset();let vo = this.viewportOffset.matrix.clone();let sm = this.surfaceMatrix.multiply.apply(this.surfaceMatrix, _.toArray(v));return vo.multiply.apply(vo, _.toArray(sm));},graphicMove: function(clientX, clientY){let dx = clientX;let dy = clientY;this.translateSurface(dx, dy);return this;},zoomBy: function(byF, clientX, clientY){let s = ZUI.PositionToScale(this.zoom + byF);this.zoomSet(s, clientX, clientY);return this;},zoomSet: function(zoom, clientX, clientY) {let newScale = this.fitToLimits(zoom);this.zoom = ZUI.ScaleToPosition(newScale);if (newScale === this.scale) {return this;}let sf = this.clientToSurface(clientX, clientY);let scaleBy = newScale / this.scale;this.surfaceMatrix.scale(scaleBy);this.scale = newScale;let c = this.surfaceToClient(sf);let dx = clientX - c.x;let dy = clientY - c.y;this.translateSurface(dx, dy);return this;},translateSurface: function(x, y) {ZUI.TranslateMatrix(this.surfaceMatrix, x, y);this.updateSurface();return this;},updateOffset: function() {let rect = this.viewport.getBoundingClientRect();_.extend(this.viewportOffset, rect);this.viewportOffset.left -= document.body.scrollLeft;this.viewportOffset.top -= document.body.scrollTop;this.viewportOffset.matrix.identity().translate(this.viewportOffset.left, this.viewportOffset.top);return this;},updateSurface: function() {let e = this.surfaceMatrix.elements;for(let i = 0; i < this.surfaces.length; i++){this.surfaces[i].apply(e[2], e[5], e[0]);}return this;},reset: function() {this.zoom = 0;this.scale = 1.0;this.surfaceMatrix.identity();return this;},fitToLimits: function(s) {return ZUI.Clamp(s, this.limits.scale.min, this.limits.scale.max);}});}) ((typeof global !== 'undefined' ? global : (this || window)).Two);整個項目打包下載地址:
https://github.com/fengfanchen/frontUI/tree/master/mouseDemo
總結
以上是生活随笔為你收集整理的计算机图形学Web前端笔记-图形平移放缩原理及实现(two.js鼠标事件适用所有渲染)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cuda笔记-GPU多线程的奇偶排序
- 下一篇: 2017年html5行业报告,云适配发布