Skip to content

Commit

Permalink
Add a viewport example/test.
Browse files Browse the repository at this point in the history
Tested with an iPad 2.

This example shows a 400x200 viewport of an 800x400 display.

It tries to be intelligent about how much it redraws. It copies what
it can, and then when the user releases the mouse, it redraws the
"dirty" areas that were newly revealed.
  • Loading branch information
kanaka committed Aug 3, 2011
1 parent ce3bdbc commit 4245363
Showing 1 changed file with 244 additions and 0 deletions.
244 changes: 244 additions & 0 deletions tests/viewport.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
<!DOCTYPE html>
<html>
<head><title>Viewport Test</title></head>
<body>
<br><br>

Canvas:
<input id="move-selector" type="button" value="Move"
onclick="toggleMove();">
<br>
<canvas id="canvas" width="640" height="20"
style="border-style: dotted; border-width: 1px;">
Canvas not supported.
</canvas>

<br>
Results:<br>
<textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
</body>

<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../include/base64.js"></script>
<script src="../include/input.js"></script>
<script src="../include/display.js"></script>
<script>
var msg_cnt = 0, iterations,
fb_width = 800,
fb_height = 600,
viewport = {
'x': 0, 'y': 0,
'w' : 400, 'h' : 200 },
cleanRect = {},
penDown = false, doMove = false,
inMove = false, lastPos = {},
canvas, ctx, keyboard, mouse;

var newline = "\n";
if (Util.Engine.trident) {
var newline = "<br>\n";
}

function message(str) {
console.log(str);
cell = $D('messages');
cell.innerHTML += msg_cnt + ": " + str + newline;
cell.scrollTop = cell.scrollHeight;
msg_cnt++;
}

function mouseButton(x, y, down, bmask) {
//msg = 'mouse x,y: ' + x + ',' + y + ' down: ' + down;
//msg += ' bmask: ' + bmask;
//message(msg);

if (doMove) {
if (down && !inMove) {
inMove = true;
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) {
inMove = false;
dirtyRedraw();
}
return;
}

if (down && ! penDown) {
penDown = true;
ctx.beginPath();
ctx.moveTo(x, y);
} else if (!down && penDown) {
penDown = false;
ctx.closePath();
}
}

function mouseMove(x, y) {
var deltaX, deltaY, x1, y1;

if (inMove) {
viewportMove(x, y);
return;
}

if (penDown) {
ctx.lineTo(x, y);
ctx.stroke();
}
}

function viewportMove(x, y) {
var v = viewport, c = cleanRect,
vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1,
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);
}
v.x += deltaX;
vx2 += deltaX;

if ((v.y + deltaY) < 0) {
deltaY = - v.y;
}
if ((vy2 + deltaY) >= fb_height) {
deltaY -= ((vy2 + deltaY) - fb_height);
}
v.y += deltaY;
vy2 += deltaY;

// Update the clean rectangle
if (v.x > c.x1) {
c.x1 = v.x;
}
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() {
var v = viewport, c = cleanRect,
vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1;

if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) {
// 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) {
var imgData = ctx.createImageData(w, h),
data = imgData.data, pixel, realX, realY;

for (var i = 0; i < w; i++) {
realX = viewport.x + x + i;
for (var j = 0; j < h; j++) {
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;
}
}
//message("i: " + i + ", j: " + j + ", pixel: " + pixel);
ctx.putImageData(imgData, x, y);
}

function toggleMove() {
if (doMove) {
doMove = false;
$D('move-selector').style.backgroundColor = "";
$D('move-selector').style.color = "";
} else {
doMove = true;
$D('move-selector').style.backgroundColor = "black";
$D('move-selector').style.color = "lightgray";
}
}

window.onload = function() {
canvas = new Display({'target' : $D('canvas')});
ctx = canvas.get_context();
mouse = new Mouse({'target': $D('canvas'),
'onMouseButton': mouseButton,
'onMouseMove': mouseMove});

canvas.resize(viewport.w, viewport.h, true);
mouse.grab();
message("Display initialized");

drawArea(0, 0, viewport.w, viewport.h);
}
</script>
</html>

0 comments on commit 4245363

Please sign in to comment.