extract rendering code

This commit is contained in:
Fabian Jakobs 2010-04-02 16:22:04 +02:00
commit bf3266a83a

View file

@ -11,25 +11,25 @@
#container { #container {
position: absolute; position: absolute;
border: 1px solid black;
width: 600px; width: 600px;
height: 400px;
} }
#canvas { #container.focus {
border: 1px solid #327fbd;;
}
.canvas {
position: absolute; position: absolute;
border: 1px solid black; width: 600px;
margin: 4px;
width: 590px;
height: 400px; height: 400px;
overflow-x: auto; overflow-x: auto;
overflow-y: auto; overflow-y: auto;
font-family: Courier New; font-family: Courier New;
white-space: nowrap; white-space: nowrap;
} }
#canvas.focus {
border: 1px solid #327fbd;;
}
.composition { .composition {
position: absolute; position: absolute;
text-decoration: underline; text-decoration: underline;
@ -55,7 +55,6 @@
<body> <body>
<div id="container"> <div id="container">
<div id="canvas"></div>
</div> </div>
<script type="text/javascript" charset="utf-8"> <script type="text/javascript" charset="utf-8">
@ -229,13 +228,13 @@ function KeyBinding(element, host)
}); });
}; };
function Editor(containerId, canvasId) function Editor(renderer)
{ {
this.container = document.getElementById(containerId); var container = renderer.getContainerElement();
this.canvas = document.getElementById(canvasId); this.renderer = renderer;
var textInput = new TextInput(container, this); var textInput = new TextInput(container, this);
new KeyBinding(this.container, this); new KeyBinding(container, this);
var self = this; var self = this;
addListener(container, "mousedown", function(e) { addListener(container, "mousedown", function(e) {
@ -244,16 +243,6 @@ function Editor(containerId, canvasId)
return preventDefault(e); return preventDefault(e);
}); });
this.measureSizes();
this.composition = document.createElement("div");
this.composition.className = "composition";
this.composition.style.height = this.lineHeight + "px";
this.cursor = document.createElement("div");
this.cursor.className = "cursor";
this.cursor.style.height = this.lineHeight + "px";
this.row = 0; this.row = 0;
this.col = 0; this.col = 0;
this.lines = [""]; this.lines = [""];
@ -261,103 +250,30 @@ function Editor(containerId, canvasId)
this.draw(); this.draw();
} }
Editor.prototype = { Editor.prototype =
{
measureSizes : function()
{
var measureNode = document.createElement("div");
var style = measureNode.style;
style.width = style.height = "auto";
style.left = style.top = "-1000px";
style.visibility = "hidden";
style.position = "absolute";
style.overflow = "visible";
measureNode.innerHTML = "X<br>X";
this.canvas.appendChild(measureNode);
this.lineHeight = Math.round(measureNode.offsetHeight / 2);
this.characterWidth = measureNode.offsetWidth;
this.canvas.removeChild(measureNode);
},
draw : function() draw : function()
{ {
if (this.cursor.parentNode) { this.renderer.draw(this.lines);
this.canvas.removeChild(this.cursor); this.renderer.updateCursor(this.row, this.col);
}
// TODO HACK
var longestLine = this.canvas.clientWidth;
for (var i=0; i < this.lines.length; i++) {
longestLine = Math.max(longestLine, (this.lines[i].length * this.characterWidth));
}
var html = [];
for (var i=0; i < this.lines.length; i++)
{
html.push(
"<div class='line ",
i % 2 == 0 ? "even" : "odd",
"' style='height:" + this.lineHeight + "px;",
"width:", longestLine, "px'>",
this.lines[i].
replace(/&/g, "&amp;").
replace(/</g, "&lt;").
replace(/\s/g, "&nbsp;"),
"</div>"
);
};
this.canvas.innerHTML = html.join("");
this.updateCursor();
}, },
updateCursor : function() updateCursor : function() {
{ this.renderer.updateCursor(this.row, this.col);
var left = this.col * this.characterWidth;
var top = this.row * this.lineHeight;
this.cursor.style.left = left + "px";
this.cursor.style.top = top + "px";
this.canvas.appendChild(this.cursor);
if (this.canvas.scrollLeft > left) {
this.canvas.scrollLeft = left;
}
if (this.canvas.scrollLeft + this.canvas.clientWidth < left + this.characterWidth) {
this.canvas.scrollLeft = left + this.characterWidth - this.canvas.clientWidth;
}
if (this.canvas.scrollTop > top) {
this.canvas.scrollTop = top;
}
if (this.canvas.scrollTop + this.canvas.clientHeight < top + this.lineHeight) {
this.canvas.scrollTop = top + this.lineHeight - this.canvas.clientHeight;
}
}, },
onFocus : function() { onFocus : function() {
this.canvas.className = "focus"; this.renderer.visualizeFocus();
}, },
onBlur : function() { onBlur : function() {
this.canvas.className = ""; this.renderer.visualizeBlur();
}, },
placeCursorToMouse : function(pageX, pageY) placeCursorToMouse : function(pageX, pageY)
{ {
var canvas = this.canvas; var pos = this.renderer.screenToTextCoordinates(pageX, pageY);
var canvasPos = canvas.getBoundingClientRect(); this.moveTo(pos.row, pos.column);
var row = Math.floor((pageY + canvas.scrollTop - canvasPos.top) / this.lineHeight);
var col = Math.floor((pageX + canvas.scrollLeft - canvasPos.left) / this.characterWidth);
this.moveTo(row, col)
}, },
onTextInput: function(text) onTextInput: function(text)
@ -443,25 +359,16 @@ Editor.prototype = {
onCompositionStart : function() onCompositionStart : function()
{ {
setText(this.composition, ""); this.renderer.showComposition(this.row, this.col);
this.composition.style.left = (this.col * this.characterWidth) + "px";
this.composition.style.top = (this.row * this.lineHeight) + "px";
this.onTextInput(" "); this.onTextInput(" ");
this.canvas.appendChild(this.composition);
}, },
onCompositionUpdate : function(text) { onCompositionUpdate : function(text) {
setText(this.composition, text); this.renderer.setCompositionText(text);
}, },
onCompositionEnd : function() { onCompositionEnd : function() {
if (this.composition.parentNode) { this.renderer.hideComposition();
this.canvas.removeChild(this.composition);
}
this.removeLeft(); this.removeLeft();
}, },
@ -473,7 +380,8 @@ Editor.prototype = {
this.moveBy(1, 0); this.moveBy(1, 0);
}, },
moveLeft : function() { moveLeft : function()
{
if (this.col == 0) { if (this.col == 0) {
if (this.row > 0) { if (this.row > 0) {
this.moveTo(this.row-1, this.lines[this.row-1].length); this.moveTo(this.row-1, this.lines[this.row-1].length);
@ -513,7 +421,159 @@ Editor.prototype = {
} }
} }
new Editor("container", "canvas", "text");
function DumbRenderer(containerId)
{
this.container = document.getElementById(containerId);
this.canvas = document.createElement("div");
this.canvas.className = "canvas";
this.container.appendChild(this.canvas);
this._measureSizes();
this.composition = document.createElement("div");
this.composition.className = "composition";
this.composition.style.height = this.lineHeight + "px";
this.cursor = document.createElement("div");
this.cursor.className = "cursor";
this.cursor.style.height = this.lineHeight + "px";
}
DumbRenderer.prototype =
{
getContainerElement : function() {
return this.container;
},
_measureSizes : function()
{
var measureNode = document.createElement("div");
var style = measureNode.style;
style.width = style.height = "auto";
style.left = style.top = "-1000px";
style.visibility = "hidden";
style.position = "absolute";
style.overflow = "visible";
measureNode.innerHTML = "X<br>X";
this.canvas.appendChild(measureNode);
this.lineHeight = Math.round(measureNode.offsetHeight / 2);
this.characterWidth = measureNode.offsetWidth;
this.canvas.removeChild(measureNode);
},
draw : function(lines)
{
// TODO HACK
var longestLine = this.canvas.clientWidth;
for (var i=0; i < lines.length; i++) {
longestLine = Math.max(longestLine, (lines[i].length * this.characterWidth));
}
var html = [];
for (var i=0; i < lines.length; i++)
{
html.push(
"<div class='line ",
i % 2 == 0 ? "even" : "odd",
"' style='height:" + this.lineHeight + "px;",
"width:", longestLine, "px'>",
lines[i].
replace(/&/g, "&amp;").
replace(/</g, "&lt;").
replace(/\s/g, "&nbsp;"),
"</div>"
);
};
this.canvas.innerHTML = html.join("");
this.canvas.appendChild(this.cursor)
},
updateCursor : function(row, column)
{
var left = column * this.characterWidth;
var top = row * this.lineHeight;
this.cursor.style.left = left + "px";
this.cursor.style.top = top + "px";
this.canvas.appendChild(this.cursor);
if (this.canvas.scrollLeft > left) {
this.canvas.scrollLeft = left;
}
if (this.canvas.scrollLeft + this.canvas.clientWidth < left + this.characterWidth) {
this.canvas.scrollLeft = left + this.characterWidth - this.canvas.clientWidth;
}
if (this.canvas.scrollTop > top) {
this.canvas.scrollTop = top;
}
if (this.canvas.scrollTop + this.canvas.clientHeight < top + this.lineHeight) {
this.canvas.scrollTop = top + this.lineHeight - this.canvas.clientHeight;
}
},
screenToTextCoordinates : function(pageX, pageY)
{
var canvas = this.canvas;
var canvasPos = canvas.getBoundingClientRect();
if (pageX < canvasPos.left || pageX > canvasPos.right) {
row = null;
} else {
var row = Math.floor((pageY + canvas.scrollTop - canvasPos.top) / this.lineHeight);
}
if (pageY < canvasPos.top || pageY > canvasPos.bottom) {
col = null;
} else {
var col = Math.floor((pageX + canvas.scrollLeft - canvasPos.left) / this.characterWidth);
}
return {
row: row,
column: col
}
},
visualizeFocus : function() {
this.container.className = "focus";
},
visualizeBlur : function() {
this.container.className = "";
},
showComposition : function(row, column)
{
setText(this.composition, "");
this.composition.style.left = (column * this.characterWidth+1) + "px";
this.composition.style.top = (row * this.lineHeight+1) + "px";
this.container.appendChild(this.composition);
},
setCompositionText : function(text) {
setText(this.composition, text);
},
hideComposition : function() {
if (this.composition.parentNode) {
this.container.removeChild(this.composition);
}
}
}
new Editor(new DumbRenderer("container"), "text");
</script> </script>