Viewport handling in include/display.js
Part of mobile device support: https://github.com/kanaka/noVNC/issues/48 The Display object is redefined as a larger display region with an equal or smaller visible viewport. The size of the full display region is set/changed using resize(). The viewport is set/changed using viewportChange(). All exposed routines that draw on the display now take coordinates that are absolute (relative to the full display region). For example, the result of fillRect(100, 100, 10, 10, [255,0,0]) will appear in the canvas at (0,0) if the viewport is set to (100,100). Details: - Move the generic part of the viewport code from tests/viewport.html into include/display. - Add two new routines to the Display interface: - viewportChange(deltaX, deltaY, width, height) - This adjusts the position of the visible viewport and/or the size of the viewport. - deltaX and deltaY specify how the position of the viewport should be shifted. The position of the viewport is clamped to the full region size (i.e. cannot outside the display region). - The clean and dirty regions of the display are updated based on calls to this routine. For example, if the viewport width is increased, then there is now a dirty box on the right side of the viewport. Another example, if the viewport is shifted down and to the left over the display region, there are now two dirty boxes: one on the left side and one on the bottom of the viewport. - getCleanDirtyReset() - This returns an object with the clean box and a list of dirty boxes (that need to be redrawn). {'cleanBox': {'x': x, 'y': y, 'w': w, 'h': h}, 'dirtyBoxes': [{'x': x, 'y': y, 'w': w, 'h': h}, ...] } - The coordinates in the clean and dirty boxes are absolute coordinates (relative to the full display region) but they are clipped to the visible viewport. - Calling this function also resets the clean rectangle to be the whole viewport (i.e. nothing visible needs to be redrawn dirty) so the caller of this routine is responsible for redrawing any
This commit is contained in:
parent
afecb83988
commit
54e7cbdf8f
|
@ -25,8 +25,12 @@ var that = {}, // Public API methods
|
||||||
imageDataCreate, imageDataGet, rgbxImageData, cmapImageData,
|
imageDataCreate, imageDataGet, rgbxImageData, cmapImageData,
|
||||||
rgbxImageFill, cmapImageFill, setFillColor, rescale, flush,
|
rgbxImageFill, cmapImageFill, setFillColor, rescale, flush,
|
||||||
|
|
||||||
c_width = 0,
|
// The full frame buffer (logical canvas) size
|
||||||
c_height = 0,
|
fb_width = 0,
|
||||||
|
fb_height = 0,
|
||||||
|
// The visible "physical canvas" viewport
|
||||||
|
viewport = {'x': 0, 'y': 0, 'w' : 0, 'h' : 0 },
|
||||||
|
cleanRect = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1},
|
||||||
|
|
||||||
c_prevStyle = "",
|
c_prevStyle = "",
|
||||||
|
|
||||||
|
@ -55,11 +59,11 @@ that.get_context = function () { return c_ctx; };
|
||||||
|
|
||||||
that.set_scale = function(scale) { rescale(scale); };
|
that.set_scale = function(scale) { rescale(scale); };
|
||||||
|
|
||||||
that.set_width = function (val) { that.resize(val, c_height); };
|
that.set_width = function (val) { that.resize(val, fb_height); };
|
||||||
that.get_width = function() { return c_width; };
|
that.get_width = function() { return fb_width; };
|
||||||
|
|
||||||
that.set_height = function (val) { that.resize(c_width, val); };
|
that.set_height = function (val) { that.resize(fb_width, val); };
|
||||||
that.get_height = function() { return c_height; };
|
that.get_height = function() { return fb_height; };
|
||||||
|
|
||||||
that.set_prefer_js = function(val) {
|
that.set_prefer_js = function(val) {
|
||||||
if (val && c_forceCanvas) {
|
if (val && c_forceCanvas) {
|
||||||
|
@ -217,7 +221,10 @@ rescale = function(factor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (factor > 1.0) {
|
|
||||||
|
if (typeof(factor) === "undefined") {
|
||||||
|
factor = conf.scale;
|
||||||
|
} else if (factor > 1.0) {
|
||||||
factor = 1.0;
|
factor = 1.0;
|
||||||
} else if (factor < 0.1) {
|
} else if (factor < 0.1) {
|
||||||
factor = 0.1;
|
factor = 0.1;
|
||||||
|
@ -234,6 +241,174 @@ rescale = function(factor) {
|
||||||
c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)";
|
c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
that.viewportChange = function(deltaX, deltaY, width, height) {
|
||||||
|
var c = conf.target, v = viewport, cr = cleanRect,
|
||||||
|
saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h;
|
||||||
|
|
||||||
|
if (typeof(deltaX) === "undefined") { deltaX = 0; }
|
||||||
|
if (typeof(deltaY) === "undefined") { deltaY = 0; }
|
||||||
|
if (typeof(width) === "undefined") { width = v.w; }
|
||||||
|
if (typeof(height) === "undefined") { height = v.h; }
|
||||||
|
|
||||||
|
// Size change
|
||||||
|
|
||||||
|
if (width > fb_width) { width = fb_width; }
|
||||||
|
if (height > fb_height) { height = fb_height; }
|
||||||
|
|
||||||
|
if ((v.w !== width) || (v.h !== height)) {
|
||||||
|
// Change width
|
||||||
|
if ((width < v.w) && (cr.x2 > v.x + width -1)) {
|
||||||
|
cr.x2 = v.x + width - 1;
|
||||||
|
}
|
||||||
|
v.w = width;
|
||||||
|
|
||||||
|
// Change height
|
||||||
|
if ((height < v.h) && (cr.y2 > v.y + height -1)) {
|
||||||
|
cr.y2 = v.y + height - 1;
|
||||||
|
}
|
||||||
|
v.h = height;
|
||||||
|
|
||||||
|
|
||||||
|
if (v.w > 0 && v.h > 0) {
|
||||||
|
saveImg = c_ctx.getImageData(0, 0,
|
||||||
|
(c.width < v.w) ? c.width : v.w,
|
||||||
|
(c.height < v.h) ? c.height : v.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
c.width = v.w;
|
||||||
|
c.height = v.h;
|
||||||
|
|
||||||
|
if (saveImg) {
|
||||||
|
c_ctx.putImageData(saveImg, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vx2 = v.x + v.w - 1;
|
||||||
|
vy2 = v.y + v.h - 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Position change
|
||||||
|
|
||||||
|
if ((deltaX < 0) && ((v.x + deltaX) < 0)) {
|
||||||
|
deltaX = - v.x;
|
||||||
|
}
|
||||||
|
if ((vx2 + deltaX) >= fb_width) {
|
||||||
|
deltaX -= ((vx2 + deltaX) - fb_width + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v.y + deltaY) < 0) {
|
||||||
|
deltaY = - v.y;
|
||||||
|
}
|
||||||
|
if ((vy2 + deltaY) >= fb_height) {
|
||||||
|
deltaY -= ((vy2 + deltaY) - fb_height + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((deltaX === 0) && (deltaY === 0)) {
|
||||||
|
//message("skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
message("deltaX: " + deltaX + ", deltaY: " + deltaY);
|
||||||
|
|
||||||
|
v.x += deltaX;
|
||||||
|
vx2 += deltaX;
|
||||||
|
v.y += deltaY;
|
||||||
|
vy2 += deltaY;
|
||||||
|
|
||||||
|
// Update the clean rectangle
|
||||||
|
if (v.x > cr.x1) {
|
||||||
|
cr.x1 = v.x;
|
||||||
|
}
|
||||||
|
if (vx2 < cr.x2) {
|
||||||
|
cr.x2 = vx2;
|
||||||
|
}
|
||||||
|
if (v.y > cr.y1) {
|
||||||
|
cr.y1 = v.y;
|
||||||
|
}
|
||||||
|
if (vy2 < cr.y2) {
|
||||||
|
cr.y2 = vy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deltaX < 0) {
|
||||||
|
// Shift viewport left, redraw left section
|
||||||
|
x1 = 0;
|
||||||
|
w = - deltaX;
|
||||||
|
} else {
|
||||||
|
// Shift viewport right, redraw right section
|
||||||
|
x1 = v.w - deltaX;
|
||||||
|
w = deltaX;
|
||||||
|
}
|
||||||
|
if (deltaY < 0) {
|
||||||
|
// Shift viewport up, redraw top section
|
||||||
|
y1 = 0;
|
||||||
|
h = - deltaY;
|
||||||
|
} else {
|
||||||
|
// Shift viewport down, redraw bottom section
|
||||||
|
y1 = v.h - deltaY;
|
||||||
|
h = deltaY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the valid part of the viewport to the shifted location
|
||||||
|
saveStyle = c_ctx.fillStyle;
|
||||||
|
c_ctx.fillStyle = "rgb(255,255,255)";
|
||||||
|
if (deltaX !== 0) {
|
||||||
|
//that.copyImage(0, 0, -deltaX, 0, v.w, v.h);
|
||||||
|
//that.fillRect(x1, 0, w, v.h, [255,255,255]);
|
||||||
|
c_ctx.drawImage(c, 0, 0, v.w, v.h, -deltaX, 0, v.w, v.h);
|
||||||
|
c_ctx.fillRect(x1, 0, w, v.h);
|
||||||
|
}
|
||||||
|
if (deltaY !== 0) {
|
||||||
|
//that.copyImage(0, 0, 0, -deltaY, v.w, v.h);
|
||||||
|
//that.fillRect(0, y1, v.w, h, [255,255,255]);
|
||||||
|
c_ctx.drawImage(c, 0, 0, v.w, v.h, 0, -deltaY, v.w, v.h);
|
||||||
|
c_ctx.fillRect(0, y1, v.w, h);
|
||||||
|
}
|
||||||
|
c_ctx.fillStyle = saveStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
that.getCleanDirtyReset = function() {
|
||||||
|
var v = viewport, c = cleanRect, cleanBox, dirtyBoxes = [],
|
||||||
|
vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Copy the cleanRect
|
||||||
|
cleanBox = {'x': c.x1, 'y': c.y1,
|
||||||
|
'w': c.x2 - c.x1 + 1, 'h': c.y2 - c.y1 + 1};
|
||||||
|
|
||||||
|
if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) {
|
||||||
|
// Whole viewport is dirty
|
||||||
|
dirtyBoxes.push({'x': v.x, 'y': v.y, 'w': v.w, 'h': v.h});
|
||||||
|
} else {
|
||||||
|
// Redraw dirty regions
|
||||||
|
if (v.x < c.x1) {
|
||||||
|
// left side dirty region
|
||||||
|
dirtyBoxes.push({'x': v.x, 'y': v.y,
|
||||||
|
'w': c.x1 - v.x + 1, 'h': v.h});
|
||||||
|
}
|
||||||
|
if (vx2 > c.x2) {
|
||||||
|
// right side dirty region
|
||||||
|
dirtyBoxes.push({'x': c.x2 + 1, 'y': v.y,
|
||||||
|
'w': vx2 - c.x2, 'h': v.h});
|
||||||
|
}
|
||||||
|
if (v.y < c.y1) {
|
||||||
|
// top/middle dirty region
|
||||||
|
dirtyBoxes.push({'x': c.x1, 'y': v.y,
|
||||||
|
'w': c.x2 - c.x1 + 1, 'h': c.y1 - v.y});
|
||||||
|
}
|
||||||
|
if (vy2 > c.y2) {
|
||||||
|
// bottom/middle dirty region
|
||||||
|
dirtyBoxes.push({'x': c.x1, 'y': c.y2 + 1,
|
||||||
|
'w': c.x2 - c.x1 + 1, 'h': vy2 - c.y2});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the cleanRect to the whole viewport
|
||||||
|
cleanRect = {'x1': v.x, 'y1': v.y,
|
||||||
|
'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1};
|
||||||
|
|
||||||
|
return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Force canvas redraw (for webkit bug #46319 workaround)
|
// Force canvas redraw (for webkit bug #46319 workaround)
|
||||||
flush = function() {
|
flush = function() {
|
||||||
var old_val;
|
var old_val;
|
||||||
|
@ -266,27 +441,25 @@ setFillColor = function(color) {
|
||||||
//
|
//
|
||||||
|
|
||||||
that.resize = function(width, height) {
|
that.resize = function(width, height) {
|
||||||
var c = conf.target;
|
|
||||||
|
|
||||||
c_prevStyle = "";
|
c_prevStyle = "";
|
||||||
|
|
||||||
c.width = width;
|
fb_width = width;
|
||||||
c.height = height;
|
fb_height = height;
|
||||||
|
|
||||||
c_width = c.offsetWidth;
|
|
||||||
c_height = c.offsetHeight;
|
|
||||||
|
|
||||||
rescale(conf.scale);
|
rescale(conf.scale);
|
||||||
|
that.viewportChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
that.clear = function() {
|
that.clear = function() {
|
||||||
|
|
||||||
if (conf.logo) {
|
if (conf.logo) {
|
||||||
that.resize(conf.logo.width, conf.logo.height);
|
that.resize(conf.logo.width, conf.logo.height);
|
||||||
|
that.viewportChange(0, 0, conf.logo.width, conf.logo.height);
|
||||||
that.blitStringImage(conf.logo.data, 0, 0);
|
that.blitStringImage(conf.logo.data, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
that.resize(640, 20);
|
that.resize(640, 20);
|
||||||
c_ctx.clearRect(0, 0, c_width, c_height);
|
that.viewportChange(0, 0, 640, 20);
|
||||||
|
c_ctx.clearRect(0, 0, viewport.w, viewport.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No benefit over default ("source-over") in Chrome and firefox
|
// No benefit over default ("source-over") in Chrome and firefox
|
||||||
|
@ -295,12 +468,13 @@ that.clear = function() {
|
||||||
|
|
||||||
that.fillRect = function(x, y, width, height, color) {
|
that.fillRect = function(x, y, width, height, color) {
|
||||||
setFillColor(color);
|
setFillColor(color);
|
||||||
c_ctx.fillRect(x, y, width, height);
|
c_ctx.fillRect(x - viewport.x, y - viewport.y, width, height);
|
||||||
};
|
};
|
||||||
|
|
||||||
that.copyImage = function(old_x, old_y, new_x, new_y, width, height) {
|
that.copyImage = function(old_x, old_y, new_x, new_y, w, h) {
|
||||||
c_ctx.drawImage(conf.target, old_x, old_y, width, height,
|
var x1 = old_x - viewport.x, y1 = old_y - viewport.y,
|
||||||
new_x, new_y, width, height);
|
x2 = new_x - viewport.x, y2 = new_y - viewport.y;
|
||||||
|
c_ctx.drawImage(conf.target, x1, y1, w, h, x2, y2, w, h);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -386,7 +560,7 @@ rgbxImageData = function(x, y, width, height, arr, offset) {
|
||||||
data[i + 2] = arr[j + 2];
|
data[i + 2] = arr[j + 2];
|
||||||
data[i + 3] = 255; // Set Alpha
|
data[i + 3] = 255; // Set Alpha
|
||||||
}
|
}
|
||||||
c_ctx.putImageData(img, x, y);
|
c_ctx.putImageData(img, x - viewport.x, y - viewport.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
// really slow fallback if we don't have imageData
|
// really slow fallback if we don't have imageData
|
||||||
|
@ -414,7 +588,7 @@ cmapImageData = function(x, y, width, height, arr, offset) {
|
||||||
data[i + 2] = rgb[2];
|
data[i + 2] = rgb[2];
|
||||||
data[i + 3] = 255; // Set Alpha
|
data[i + 3] = 255; // Set Alpha
|
||||||
}
|
}
|
||||||
c_ctx.putImageData(img, x, y);
|
c_ctx.putImageData(img, x - viewport.x, y - viewport.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
cmapImageFill = function(x, y, width, height, arr, offset) {
|
cmapImageFill = function(x, y, width, height, arr, offset) {
|
||||||
|
@ -441,7 +615,9 @@ that.blitImage = function(x, y, width, height, arr, offset) {
|
||||||
|
|
||||||
that.blitStringImage = function(str, x, y) {
|
that.blitStringImage = function(str, x, y) {
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.onload = function () { c_ctx.drawImage(img, x, y); };
|
img.onload = function () {
|
||||||
|
c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
|
||||||
|
};
|
||||||
img.src = str;
|
img.src = str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,28 @@
|
||||||
.fullscreen {
|
html,body {
|
||||||
display: block;
|
margin: 0px;
|
||||||
position: absolute;
|
padding: 0px;
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 9999;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-layout {
|
.flex-layout {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
display: box;
|
display: box;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
display: -moz-box;
|
display: -moz-box;
|
||||||
display: -ms-box;
|
display: -ms-box;
|
||||||
|
|
||||||
box-orient: vertical;
|
box-orient: vertical;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-moz-box-orient: vertical;
|
-moz-box-orient: vertical;
|
||||||
-ms-box-orient: vertical;
|
-ms-box-orient: vertical;
|
||||||
|
|
||||||
|
box-align: stretch;
|
||||||
|
-webkit-box-align: stretch;
|
||||||
|
-moz-box-align: stretch;
|
||||||
|
-ms-box-align: stretch;
|
||||||
}
|
}
|
||||||
.flex-box {
|
.flex-box {
|
||||||
box-flex: 1;
|
box-flex: 1;
|
||||||
|
@ -27,3 +31,13 @@
|
||||||
-ms-box-flex: 1;
|
-ms-box-flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas {
|
||||||
|
position: absolute;
|
||||||
|
border-style: dotted;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
|
@ -782,6 +782,7 @@ init_msg = function() {
|
||||||
|
|
||||||
display.set_true_color(conf.true_color);
|
display.set_true_color(conf.true_color);
|
||||||
display.resize(fb_width, fb_height);
|
display.resize(fb_width, fb_height);
|
||||||
|
display.viewportChange(0, 0, fb_width, fb_height);
|
||||||
keyboard.grab();
|
keyboard.grab();
|
||||||
mouse.grab();
|
mouse.grab();
|
||||||
|
|
||||||
|
@ -1312,6 +1313,7 @@ encHandlers.DesktopSize = function set_desktopsize() {
|
||||||
fb_width = FBU.width;
|
fb_width = FBU.width;
|
||||||
fb_height = FBU.height;
|
fb_height = FBU.height;
|
||||||
display.resize(fb_width, fb_height);
|
display.resize(fb_width, fb_height);
|
||||||
|
display.viewportChange(0, 0, fb_width, fb_height);
|
||||||
timing.fbu_rt_start = (new Date()).getTime();
|
timing.fbu_rt_start = (new Date()).getTime();
|
||||||
// Send a new non-incremental request
|
// Send a new non-incremental request
|
||||||
ws.send(fbUpdateRequest(0));
|
ws.send(fbUpdateRequest(0));
|
||||||
|
|
|
@ -9,29 +9,25 @@
|
||||||
<meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=no">
|
<meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="fullscreen flex-layout">
|
<div class="flex-layout">
|
||||||
|
<div>
|
||||||
<div>
|
Canvas:
|
||||||
Canvas:
|
<input id="move-selector" type="button" value="Move"
|
||||||
<input id="move-selector" type="button" value="Move"
|
onclick="toggleMove();">
|
||||||
onclick="toggleMove();">
|
<br>
|
||||||
<br>
|
</div>
|
||||||
|
<div class="container flex-box">
|
||||||
|
<canvas id="canvas" class="canvas">
|
||||||
|
Canvas not supported.
|
||||||
|
</canvas>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<br>
|
||||||
|
Results:<br>
|
||||||
|
<textarea id="messages" style="font-size: 9;" cols=80 rows=8></textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="container" class="flex-box">
|
|
||||||
<canvas id="canvas"
|
|
||||||
style="border-style: dotted; border-width: 1px;">
|
|
||||||
Canvas not supported.
|
|
||||||
</canvas>
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<br>
|
|
||||||
Results:<br>
|
|
||||||
<textarea id="messages" style="font-size: 9;" cols=80 rows=8></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -45,13 +41,10 @@
|
||||||
<script src="../include/display.js"></script>
|
<script src="../include/display.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var msg_cnt = 0, iterations,
|
var msg_cnt = 0, iterations,
|
||||||
fb_width = 800,
|
|
||||||
fb_height = 768,
|
|
||||||
viewport = {'x': 0, 'y': 0, 'w' : 0, 'h' : 0 },
|
|
||||||
cleanRect = {},
|
|
||||||
penDown = false, doMove = false,
|
penDown = false, doMove = false,
|
||||||
inMove = false, lastPos = {},
|
inMove = false, lastPos = {},
|
||||||
canvas, ctx, keyboard, mouse;
|
padW = 0, padH = 0,
|
||||||
|
display, ctx, keyboard, mouse;
|
||||||
|
|
||||||
var newline = "\n";
|
var newline = "\n";
|
||||||
if (Util.Engine.trident) {
|
if (Util.Engine.trident) {
|
||||||
|
@ -75,14 +68,9 @@
|
||||||
if (down && !inMove) {
|
if (down && !inMove) {
|
||||||
inMove = true;
|
inMove = true;
|
||||||
lastPos = {'x': x, 'y': y};
|
lastPos = {'x': x, 'y': y};
|
||||||
cleanRect = {
|
|
||||||
'x1': viewport.x,
|
|
||||||
'y1': viewport.y,
|
|
||||||
'x2': viewport.x + viewport.w - 1,
|
|
||||||
'y2': viewport.y + viewport.h - 1};
|
|
||||||
} else if (!down && inMove) {
|
} else if (!down && inMove) {
|
||||||
inMove = false;
|
inMove = false;
|
||||||
dirtyRedraw();
|
//dirtyRedraw();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +89,13 @@
|
||||||
var deltaX, deltaY, x1, y1;
|
var deltaX, deltaY, x1, y1;
|
||||||
|
|
||||||
if (inMove) {
|
if (inMove) {
|
||||||
viewportMove(x, y);
|
//deltaX = x - lastPos.x; // drag viewport
|
||||||
|
deltaX = lastPos.x - x; // drag frame buffer
|
||||||
|
//deltaY = y - lastPos.y; // drag viewport
|
||||||
|
deltaY = lastPos.y - y; // drag frame buffer
|
||||||
|
lastPos = {'x': x, 'y': y};
|
||||||
|
|
||||||
|
display.viewportChange(deltaX, deltaY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,130 +105,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function viewportMove(x, y) {
|
function dirtyRedraw() {
|
||||||
var v = viewport, c = cleanRect,
|
if (inMove) {
|
||||||
vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1,
|
// Wait for user to stop moving viewport
|
||||||
deltaX, deltaY, w, h;
|
|
||||||
|
|
||||||
//deltaX = x - lastPos.x; // drag viewport
|
|
||||||
deltaX = lastPos.x - x; // drag frame buffer
|
|
||||||
//deltaY = y - lastPos.y; // drag viewport
|
|
||||||
deltaY = lastPos.y - y; // drag frame buffer
|
|
||||||
lastPos = {'x': x, 'y': y};
|
|
||||||
|
|
||||||
if ((deltaX < 0) && ((v.x + deltaX) < 0)) {
|
|
||||||
deltaX = - v.x;
|
|
||||||
}
|
|
||||||
if ((vx2 + deltaX) >= fb_width) {
|
|
||||||
deltaX -= ((vx2 + deltaX) - fb_width + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((v.y + deltaY) < 0) {
|
|
||||||
deltaY = - v.y;
|
|
||||||
}
|
|
||||||
if ((vy2 + deltaY) >= fb_height) {
|
|
||||||
deltaY -= ((vy2 + deltaY) - fb_height + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((deltaX === 0) && (deltaY === 0)) {
|
|
||||||
//message("skipping");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message("deltaX: " + deltaX + ", deltaY: " + deltaY);
|
|
||||||
|
|
||||||
v.x += deltaX;
|
var d = display.getCleanDirtyReset();
|
||||||
vx2 += deltaX;
|
|
||||||
v.y += deltaY;
|
|
||||||
vy2 += deltaY;
|
|
||||||
|
|
||||||
// Update the clean rectangle
|
for (i = 0; i < d.dirtyBoxes.length; i++) {
|
||||||
if (v.x > c.x1) {
|
//showBox(d.dirtyBoxes[i], "dirty[" + i + "]: ");
|
||||||
c.x1 = v.x;
|
drawArea(d.dirtyBoxes[i]);
|
||||||
}
|
|
||||||
if (vx2 < c.x2) {
|
|
||||||
c.x2 = vx2;
|
|
||||||
}
|
|
||||||
if (v.y > c.y1) {
|
|
||||||
c.y1 = v.y;
|
|
||||||
}
|
|
||||||
if (vy2 < c.y2) {
|
|
||||||
c.y2 = vy2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deltaX < 0) {
|
|
||||||
// Shift viewport left, redraw left section
|
|
||||||
x1 = 0;
|
|
||||||
w = - deltaX;
|
|
||||||
} else {
|
|
||||||
// Shift viewport right, redraw right section
|
|
||||||
x1 = v.w - deltaX;
|
|
||||||
w = deltaX;
|
|
||||||
}
|
|
||||||
if (deltaY < 0) {
|
|
||||||
// Shift viewport up, redraw top section
|
|
||||||
y1 = 0;
|
|
||||||
h = - deltaY;
|
|
||||||
} else {
|
|
||||||
// Shift viewport down, redraw bottom section
|
|
||||||
y1 = v.h - deltaY;
|
|
||||||
h = deltaY;
|
|
||||||
}
|
|
||||||
if (deltaX !== 0) {
|
|
||||||
canvas.copyImage(0, 0, -deltaX, 0, v.w, v.h);
|
|
||||||
canvas.fillRect(x1, 0, w, v.h, [255,255,255]);
|
|
||||||
}
|
|
||||||
if (deltaY !== 0) {
|
|
||||||
canvas.copyImage(0, 0, 0, -deltaY, v.w, v.h);
|
|
||||||
canvas.fillRect(0, y1, v.w, h, [255,255,255]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dirtyRedraw() {
|
function drawArea(b) {
|
||||||
var v = viewport, c = cleanRect,
|
var data = [], pixel, x, y;
|
||||||
vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1;
|
|
||||||
|
|
||||||
if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) {
|
//message("draw "+b.x+","+b.y+" ("+b.w+","+b.h+")");
|
||||||
// Nothing clean, redraw everything
|
|
||||||
drawArea(0, 0, v.w, v.h);
|
|
||||||
} else {
|
|
||||||
// Redraw dirty regions
|
|
||||||
if (v.x < c.x1) {
|
|
||||||
// redraw left side dirty region
|
|
||||||
drawArea(0, 0, c.x1 - v.x, v.h);
|
|
||||||
}
|
|
||||||
if (vx2 > c.x2) {
|
|
||||||
// redraw right side dirty region
|
|
||||||
drawArea(v.w - (vx2 - c.x2), 0, vx2 - c.x2, v.h);
|
|
||||||
}
|
|
||||||
if (v.y < c.y1) {
|
|
||||||
// redraw top/middle dirty region
|
|
||||||
drawArea(c.x1 - v.x, 0, c.x2 - c.x1 + 1, c.y1 - v.y);
|
|
||||||
}
|
|
||||||
if (vy2 > c.y2) {
|
|
||||||
// redraw bottom/middle dirty region
|
|
||||||
drawArea(c.x1 - v.x, c.y2 - v.y, c.x2 - c.x1 + 1, v.h - (c.y2 - v.y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawArea(x, y, w, h) {
|
for (var i = 0; i < b.w; i++) {
|
||||||
message("draw "+x+","+y+" ("+w+","+h+")");
|
x = b.x + i;
|
||||||
var imgData = ctx.createImageData(w, h),
|
for (var j = 0; j < b.h; j++) {
|
||||||
data = imgData.data, pixel, realX, realY;
|
y = b.y + j;
|
||||||
|
pixel = (j * b.w * 4 + i * 4);
|
||||||
for (var i = 0; i < w; i++) {
|
data[pixel + 0] = ((x * y) / 13) % 256;
|
||||||
realX = viewport.x + x + i;
|
data[pixel + 1] = ((x * y) + 392) % 256;
|
||||||
for (var j = 0; j < h; j++) {
|
data[pixel + 2] = ((x + y) + 256) % 256;
|
||||||
realY = viewport.y + y + j;
|
|
||||||
pixel = (j * w * 4 + i * 4);
|
|
||||||
data[pixel + 0] = ((realX * realY) / 13) % 256;
|
|
||||||
data[pixel + 1] = ((realX * realY) + 392) % 256;
|
|
||||||
data[pixel + 2] = ((realX + realY) + 256) % 256;
|
|
||||||
data[pixel + 3] = 255;
|
data[pixel + 3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//message("i: " + i + ", j: " + j + ", pixel: " + pixel);
|
//message("i: " + i + ", j: " + j + ", pixel: " + pixel);
|
||||||
ctx.putImageData(imgData, x, y);
|
display.blitImage(b.x, b.y, b.w, b.h, data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMove() {
|
function toggleMove() {
|
||||||
|
@ -249,36 +151,37 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onresize = function() {
|
function detectPad() {
|
||||||
var v = viewport,
|
var c = $D('canvas'), p = c.parentNode;
|
||||||
cw = $D('container').offsetWidth,
|
c.width = 10;
|
||||||
ch = $D('container').offsetHeight;
|
c.height = 10;
|
||||||
|
padW = c.offsetWidth - 10;
|
||||||
|
padH = c.offsetHeight - 10;
|
||||||
|
message("padW: " + padW + ", padH: " + padH);
|
||||||
|
}
|
||||||
|
|
||||||
message("container: " + cw + "," + ch);
|
function doResize() {
|
||||||
|
var p = $D('canvas').parentNode;
|
||||||
if (cw > fb_width) {
|
message("doResize1: [" + (p.offsetWidth - padW) +
|
||||||
cw = fb_width;
|
"," + (p.offsetHeight - padH) + "]");
|
||||||
}
|
display.viewportChange(0, 0,
|
||||||
if (ch > fb_height) {
|
p.offsetWidth - padW, p.offsetHeight - padH);
|
||||||
ch = fb_height;
|
}
|
||||||
}
|
|
||||||
if ((cw !== v.w) || (ch !== v.h)) {
|
|
||||||
v.w = cw;
|
|
||||||
v.h = ch;
|
|
||||||
message("new viewport: " + v.w + "," + v.h);
|
|
||||||
canvas.resize(v.w, v.h);
|
|
||||||
drawArea(0, 0, v.w, v.h);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
canvas = new Display({'target' : $D('canvas')});
|
detectPad();
|
||||||
ctx = canvas.get_context();
|
display = new Display({'target': $D('canvas')});
|
||||||
|
display.resize(1600, 1024);
|
||||||
|
//display.resize(800, 600);
|
||||||
|
ctx = display.get_context();
|
||||||
mouse = new Mouse({'target': $D('canvas'),
|
mouse = new Mouse({'target': $D('canvas'),
|
||||||
'onMouseButton': mouseButton,
|
'onMouseButton': mouseButton,
|
||||||
'onMouseMove': mouseMove});
|
'onMouseMove': mouseMove});
|
||||||
|
|
||||||
window.onresize();
|
Util.addEvent(window, 'resize', doResize);
|
||||||
|
//doResize();
|
||||||
|
setTimeout(doResize, 1);
|
||||||
|
setInterval(dirtyRedraw, 50);
|
||||||
mouse.grab();
|
mouse.grab();
|
||||||
|
|
||||||
message("Display initialized");
|
message("Display initialized");
|
||||||
|
|
Loading…
Reference in New Issue