PDA

View Full Version : Web page Annotations: DOM, DHTML



roxyroolz
Jul 19th, 2005, 12:47 AM
Hello all

I am looking to develop an application that basically allows users to annotate web content. I mean something like what iMarkup does. What it does is, (if I understand correctly) that it places an overlay on the web content, and allows the user to select a pen from a menu and write freeform on the "canvas", and saves the same. When the same webpage is reopened on a later date it basically restores the annotations.

http://www.imarkup.com/products/imarkup_client.asp

I am stymied here, I have no idea how to progress and which technologies to use. I have a basic understanding that the same is done with the aid of DOM, and DHTML, but I dont quite know what how. IMarkup installs an activeX component, but I would like to make it possible for the same application to be used on Firefox as well... so activeX is out.

Any help would be greatly appreciated.

Warm Regards
R

COBOLdinosaur
Jul 19th, 2005, 12:31 PM
A signed applet perhaps. Either way (applet or activex) it has to cross security boundaries. You are not going to do it with just javascript or any other non-intrusive technology. The requirment cannot be implemented without overridng security restrictions that are part of browser design from day one.

martin_narg
Jul 19th, 2005, 02:14 PM
EDIT: This is a simplified version of what you were asking about, purely concept.

I was just thinking, and had a bit of a play. This script is by no means anywhere near a finished article - there would need to be the save functionality at the end of it into a database/file, images handled, links handled, etc, etc, but hopefully it gives you a rough idea of a potential avenue to explore.



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Editor</title>
<script type="text/javascript">
function getHTML() {
if( /<!--start_editable-->([\w\Wa-z0-9]*)<!--end_editable-->/i.test(document.getElementsByTagName("body")[0].innerHTML) ) {
alert("Output:\n\n"+RegExp.$1);
}
}

var objEdit;
function edit(obj) {
if( mode == "view" ) {
return true; // treat as normal (non-editable) page
} else {
objEdit = obj;
document.frmInput.txt.value = obj.innerHTML; /* only using text node innerHTML values, this should be expanded up to deal with hrefs/images/etc */
document.getElementById("divInput").style.visibility = "visible";
return false;
}
}

function applyInput() { // apply changes
var s = document.frmInput.txt.value;
if( s == "" ) { // if no value in textbox, see if the node needs deleting
if( confirm("Delete element?") ) {
objEdit.parentNode.removeChild(objEdit);
} else {
objEdit.innerHTML = "&nbsp;";
}
} else {
objEdit.innerHTML = s;
}

document.getElementById("divInput").style.visibility = "hidden";
}

var mode = "editor";
function switchMode(obj) {
mode = (mode=="editor") ? "view" : "editor"; // switch between edit mode and normal mode
obj.innerHTML = mode;
}

function addClick() {
var tags = ["p","a","div","span"]; // editable html tags list
var a;
for( var i=0; i<tags.length; i++ ) {
a = document.getElementsByTagName(tags[i]);
for( var t=0; t<a.length; t++ ) {
if( a[t].className.indexOf("editor_") > -1 ) { // don't make editor controls editable!
continue;
} else {
a[t].onclick = function() { // add onclick edit event to all relevant elements
return edit(this);
}
}
}
}
}

function initEditor() {
addClick(); // apply onclick events
}

window.onload = initEditor;
</script>

<style>
body {
font-family: "Courier New", Courier, mono;
font-size: 12px;
color: black;
}

.editor_switchMode {
position: absolute;
right: 10px;
top: 10px;
padding: 10px 10px 10px 10px;
width: 70px;
height: 30px;
border: 1px solid black;
background-color: #FFFFFF;
}

.editor_textarea_div {
position: absolute;
right: 10px;
top: 112px;
width: 200px;
height: 100px;
padding: 10px 10px 10px 10px;
border: 1px solid black;
background-color: #FFFFFF;
visibility: hidden;
}

.editor_textarea {
font-family: "Courier New", Courier, mono;
font-size: 12px;
color: black;
width: 200px;
height: 100px;
}

.editor_ { }

form {
margin: 0 0 0 0;
padding: 0 0 0 0;
}
</style>
</head>

<body>
<div id="divSwitchMode" class="editor_switchMode"><nobr><b>Editor mode:</b><br></nobr><a class="editor_" href="#" onclick="switchMode(this);">editor</a><br><br><input type="button" name="btn1" value="view output" onclick="getHTML();"></div>
<div id="divInput" class="editor_textarea_div">
<form name="frmInput">
<strong>Input:</strong><br>
<textarea name="txt" id="txt" class="editor_textarea"></textarea>
<input type="button" name="btn1" value="apply" onclick="applyInput();">&nbsp;<input type="button" name="btn1" value="close" onclick="document.getElementById('divInput').style.visibility='hidden';">
</form>

</div>
<!--start_editable-->
<p>This is an editable paragraph</p>
<br>
<a href="myPage.html">This is an editable link</a>
<div>This is an editable div</div>
<br>
<a href="myPage.html">This is another editable link</a>
<!--end_editable-->
</body>
</html>


Hope this helps, sorry i didn't even attend to CSS in FF for this, but it still functions.

m_n

roxyroolz
Jul 19th, 2005, 04:48 PM
:) Thanks martin for your code snippet, tried it out, and works like a charm ofcourse. This solves a part of my big problem, the other part remains... being able to draw on web pages. As COBOLD pointed out I do need an ActiveX or a Java Applet for that, and I do realize the same.

I looked at some research papers that basically use JavaScript to interact with the browser DOM and passing the Mouse coordinates and then using ActiveX controls allow the rendering of digital ink on an overlay on the web pages.

Rather confused here :confused: How do I make Overlays on web pages and allow the user to draw on them, keeping in mind that the source document is a web page and not editable of course...

Any help will be HIGHLY appreciated...

thanks a tonne!!
R

martin_narg
Jul 19th, 2005, 05:29 PM
Hmm, this is an interesting one, I think I've got time to sit down tonight and build a DHTML drawing tool without using activeX controls.

My idea is to use a system whereby divs 1px high and 1px wide are created when the mouse moves, using a bit of maths to make different pen tip shapes (square, circular, oblique, etc) and obviously colour these divs.

The trouble is that I'm not sure how efficient this will be, whether or not it will simply be a programming exercise or have a real application. I'm sure that it's been done before - i'm not that original ;) and so will have a look around for something that another programmer may have done.

I will post up this evening when I have something further.

m_n

roxyroolz
Jul 19th, 2005, 06:33 PM
;) Thanks so much for your help... I am looking around too, and keep finding stuff which to a profi might make sense, but is rather convoluted for me... like XUL overlays etc...

With DHTML approach without ActiveX, wouldn't it be so that when one browses away from the webpage, one loses the drawings? I think for one to keep the drawings on the webpage, there would have to be local storage and retrieval, for which, one needs an ActiveX or Java Applet... correct me if I am wrong :confused:

Thanks a ToNnE for your help!
R

COBOLdinosaur
Jul 19th, 2005, 10:14 PM
You cannot access the local client resources from a page served from a web server except for a small amout of file srorage for cookies, and even that is only if it is enabled by the user.

You have three options:

An HTA ... IE only.

Activex ... IE only but there are plugins for Firefox... none of which is reliable or secure enough to recommend.

A signed java applet.

All three require the user to give consent to run.

Beagle
Jul 19th, 2005, 10:27 PM
I'm not so sure about that.

Using Martin's idea, you could read data from a file stored on the client and render the drawings. The problem, of course, is getting them stored, and the best way to do that is to ask them to download the file.

If the user draws on the page, set a flag to denote the drawing was modified. When they navigate away, using AJAX you can have the drawing data posted to the server and make a request for a drawing file. The server can then dynamically create the file contents needed to store the drawing and send them encoded as something that would require download.

It poses interesting problems, I'm not sure it can be done in the way I've described, but it's always worth a shot.

--Beagle

martin_narg
Jul 19th, 2005, 11:40 PM
I'm still working on the script, but essentially the way I was going to do this was to fire the newly generated HTML off using xmlhttp (hence the button on the right-hand editing menu that basically outputs the content of a body tag)

Either the script handling the ajax request can create a unique page on the fly, storing this url in a cookie and point to it that way, or even have the ajax handler save the html into a database and have the user pass a unique id to request it (again saved as a cookie/login/whatever other methods would be appropriate).

Also, as mentioned, it would be possible to then use this info to render out an image or manipulate it whichever way is appropriate.

there's even the option of writing a local file to the user's machine if all else fails, although this would only support IE and Firefox.

m_n

glenngv
Jul 20th, 2005, 05:02 AM
My idea is to use a system whereby divs 1px high and 1px wide are created when the mouse moves, using a bit of maths to make different pen tip shapes (square, circular, oblique, etc) and obviously colour these divs.

Draw Line, Ellipse, Oval, Circle, Polyline, Polygon, Triangle with JavaScript (http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm)

martin_narg
Jul 20th, 2005, 10:57 AM
:thumbsup: to the drawing of shapes dynamically!

I've thrown together a really really quick pen tool idea, i'll blend it with the "click and edit element content" script that I posted yesterday and update this thread shortly.

I've tested this script with Firefox, Opera, Netscape 8, and IE - although in IE it appears to be seriously bad with memory leaks - maybe that's because i've written it badly, maybe because of the inherent problems in IE with this type of endeavour, I'll look into it and no doubt go back to one of the JS gurus (nice to see glenngv in this thread, will be needing you later ;)) for further advice - anyway for the rest of the borwsers it works just great.



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>DHTML Pen Tool</title>
<script type="text/javascript">
/* DHTML Pen Script by Martin ([email protected]) */

/* menu code */
var blnMenu = null; // don't draw over the menu!
function checkSize(obj) { // validate pen tip size
if(/[^\d]{1,}/g.test(obj.value) || obj.value == "") {
alert("Invalid pen size supplied");
obj.value = 10;
}
}

/* pen tool code */
var blnMouseDown = null;
function evt_mouseup(e) { // disable drawing if mouse button not pressed
blnMouseDown = false;
}

function evt_mousedown(e) { // enable drawing if mouse down
blnMouseDown = true;
}

function evt_mousemove(e) {
if(blnMouseDown == null || blnMenu) { // make sure the pen tool is not missing any details
return;
}

if(!e) { // IE code getting event position
var e = window.event;
if(!blnMouseDown) {
draw(e.x, e.y);
}
}
else { // others
if(!blnMouseDown) {
draw(e.clientX, e.clientY);
}
}
}

function drawInkSpot(x, y, s, c) { // draw one ink spot
try {
var d = document.createElement("div"); // create the div and style it according to the menu choices
d.style.position = "absolute";
d.style.left = x+"px";
d.style.top = y+"px";
d.style.width = s+"px";
d.style.height = s+"px";
d.style.backgroundColor = c;
document.getElementsByTagName("body")[0].appendChild(d);
} catch(E) { }
}

function draw(x, y) {
drawInkSpot(x, y, parseInt(document.frm.txtSize.value), document.frm.selColour.value);
}

document.onmousedown = evt_mouseup;
document.onmouseup = evt_mousedown;
document.onmousemove = evt_mousemove;
</script>
<style>
body {
font-family: "Courier New", Courier, mono;
font-size: 12px;
color: #000000;
}

fieldset {
width: 145px;
}

input {
border: 1px solid black;
}
</style>
</head>

<body>
<fieldset onmouseover="blnMenu=true;" onmouseout="blnMenu=false;">
<legend>Testing info</legend>
<form name="frm">
<nobr>Pen size: <input type="text" name="txtSize" size="2" value="10" onkeyup="checkSize(this);">&nbsp;px<br></nobr>
<nobr>Colour:
<select name="selColour">
<option value="#483D8B">slate blue</option>
<option value="slategray">slate gray</option>
<option value="maroon">maroon</option>
<option value="tomato">tomato</option>
<option value="#000000">black</option>
<option value="#D2691E">chocolate</option>
</select>
</form>
</fieldset>
</body>
</html>

jbot
Jul 20th, 2005, 11:15 AM
look into SVG for Moz, etc, and VML for IE.

martin_narg
Jul 20th, 2005, 11:22 AM
nice one mate, will do.

cheers

m_n

jbot
Jul 20th, 2005, 11:23 AM
there's also the new <canvas> element (not IE). might be worth a play round with anyway.

roxyroolz
Jul 20th, 2005, 12:17 PM
Wow and seriously wow! : ) Thanks you guys martin and glenn, really wow. I was checking out the link Glenn sent and it is reallly helpful, and then the code from Martin! Thanks a LOAD!! I tried it on Opera, and wonderful, it works great! Will work upon trying to smoothen the curves... and make it working on IE...

Once that is done, to write these points to a file and reload them when the webpage is refreshed or opened anew... wouldnt that require a JApplet or something?

Wow really i am so happy to see all this possible in DHTML, I was thinking I would go to SVG or something, which meant a whole new approach etc, but this, saves the day!

Thanks and then sum!
~R~

roxyroolz
Jul 21st, 2005, 11:55 AM
Still playing around with Martin's script, and love it, but am unable to make the same work for IE :(

Another problem is capturing the points for saving, to allow to redraw when the document is reloaded... how may one proceed, any help would be HIGHLY appreciated!

Thanks!
R

glenngv
Jul 21st, 2005, 01:01 PM
There is a DHTML VML Editor (http://www.dynamicdrive.com/dynamicindex11/vmleditor.htm) submitted in Dynamic Drive. Of course, it only works in IE, but it's interesting to look at.

martin_narg
Jul 21st, 2005, 01:01 PM
EDIT: apologies for the numerous typos

Sorry for the delay in response, I got sidetracked last night by a cold beer and a leggy blonde.

I've slotted the two previous scripts i posted together, and have (as a test) dum[ped output to a file. I'm currently working on sending the generated code as an xmlhttp requst to be slotted into a database, and also the cookie/read saved code side of things.

This posting is realyl just a "playaround update".

m_n



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Editor</title>
<script type="text/javascript">
/* content editor */
function getHTML() {
var strOutput = document.getElementsByTagName("body")[0].innerHTML.replace(/<!--start_edit_menu-->[\w\Wa-z0-9]*<!--end_edit_menu-->/, "");

if( confirm("OK to save file, cancel to view output\nSaving will throw up a security warning - click yes again to save") ) {
if( window.ActiveXObject ) {
var objFSO = new ActiveXObject("Scripting.FileSystemObject");
var fil = objFSO.CreateTextFile("c:\\DHTML_edit_output.txt", true);
fil.Write(strOutput);
fil.Close();
alert("File created and saved to\nC:\\DHTML_edit_output.txt");
} else {
alert("Firefox file output not implemented yet - view output instead:\n"+strOutput);
}
} else {
alert("Output:\n\n"+strOutput);
}
}

var objEdit;
function edit(obj) {
if( mode == "view" ) {
return true; // treat as normal (non-editable) page
} else {
objEdit = obj;
document.frmInput.txt.value = obj.innerHTML; /* only using text node innerHTML values, this should be expanded up to deal with hrefs/images/etc */
document.frmInput.style.display = "block";
document.frmInput.txt.select();
document.frmInput.txt.focus();
return false;
}
}

function applyInput() { // apply changes
var s = document.frmInput.txt.value;
if( s == "" ) { // if no value in textbox, see if the node needs deleting
if( confirm("Delete element?") ) {
objEdit.parentNode.removeChild(objEdit);
} else {
objEdit.innerHTML = "&nbsp;";
}
} else {
objEdit.innerHTML = s;
}

document.frmInput.style.display = "none";
}

function closeInput() {
document.frmInput.style.display = "none";
}

var mode = "editor";
function switchMode(obj) {
mode = (mode=="editor") ? "view" : "editor"; // switch between edit mode and normal mode
obj.innerHTML = mode;
}

function addClick() {
var tags = ["p","a","div","span"]; // editable html tags list
var a;
for( var i=0; i<tags.length; i++ ) {
a = document.getElementsByTagName(tags[i]);
for( var t=0; t<a.length; t++ ) {
if( a[t].className.indexOf("editor_") > -1 ) { // don't make editor controls editable!
continue;
} else {
a[t].onclick = function() { // add onclick edit event to all relevant elements
return edit(this);
}
}
}
}
}

function initEditor() {
addClick(); // apply onclick events
}

window.onload = initEditor;

/* pen tool */
var blnPen = false;
/* menu code */
var blnMenu = null; // don't draw over the menu!
function checkSize(obj) { // validate pen tip size
if(/[^\d]{1,}/g.test(obj.value) || obj.value == "") {
alert("Invalid pen size supplied");
obj.value = 10;
}
}

function switchPenMode(obj) {
blnPen = (blnPen) ? false : true;
obj.innerHTML = "pen " + ((blnPen) ? "ON" : "OFF");
document.frmPen.style.display = (blnPen) ? "block" : "none";
}

/* pen tool code */
var blnMouseDown = null;
function evt_mouseup(e) { // disable drawing if mouse button not pressed
blnMouseDown = false;
}

function evt_mousedown(e) { // enable drawing if mouse down
blnMouseDown = true;
}

function evt_mousemove(e) {
if(blnMouseDown == null || blnMenu || !blnPen || mode != "editor") { // make sure the pen tool is not missing any details and activated
return;
}

var x, y;
if(!e) { // IE code getting event position
var e = window.event;
if(!blnMouseDown) {
draw(e.x, e.y);
}
}
else { // Firefox code getting event position
if(!blnMouseDown) {
draw(e.clientX, e.clientY);
}
}
}

function drawInkSpot(x, y, s, c) { // draw one ink spot
try {
var d = document.createElement("div"); // create the div and style it according to the menu choices
with(d.style) {
position = "absolute";
left = x+"px";
top = y+"px";
width = s+"px";
height = s+"px";
backgroundColor = c;
}
document.getElementsByTagName("body")[0].appendChild(d);
} catch(E) { }
}

function draw(x, y) {
drawInkSpot(x, y, parseInt(document.frmPen.txtSize.value), document.frmPen.selColour.value);
}

document.onmousedown = evt_mouseup;
document.onmouseup = evt_mousedown;
document.onmousemove = evt_mousemove;
</script>

<style>
body {
font-family: "Courier New", Courier, mono;
font-size: 12px;
color: black;
}

/* editor stylings */
.editor_div {
position: absolute;
right: 10px;
top: 10px;
width: 160px;
padding: 5px 10px 5px 10px;
border: 1px solid black;
background-color: #FFFFFF;
}

#divEditMenu textarea {
font-family: "Courier New", Courier, mono;
font-size: 12px;
color: black;
width: 158px;
height: 100px;
}

.editor_ { }

#divEditMenu form {
margin: 0 0 0 0;
padding: 0 0 0 0;
display: block;
}

#divEditMenu textarea, #divEditMenu input {
border: 1px solid black;
margin-top: 5px;
margin-bottom: 5px;
}

#divEditMenu select {
font-family: "Courier New", Courier, mono;
border: 1px solid black;
}
</style>
</head>

<body>
<!--start_edit_menu-->
<div id="divEditMenu" class="editor_div">
<nobr><strong>Editor menu</strong><br></nobr>
<a class="editor_" href="#" onclick="switchMode(this);">editor</a><br>
<input type="button" name="btn1" value="view output" onclick="getHTML();"><br>
<a class="editor_" href="#" onclick="switchPenMode(this);">pen OFF</a>
<form name="frmPen" style="display: none;">
<nobr>Pen size: <input type="text" name="txtSize" size="2" value="10" onkeyup="checkSize(this);">&nbsp;px<br></nobr>
<nobr>Colour:
<select name="selColour">
<option value="#483D8B">slate blue</option>
<option value="slategray">slate gray</option>
<option value="maroon">maroon</option>
<option value="tomato">tomato</option>
<option value="#000000">black</option>
<option value="#D2691E">chocolate</option>
</select>
</form>

<form name="frmInput" style="display: none;">
<strong>Input:</strong><br>
<textarea name="txt" id="txt"></textarea><br>
<input type="button" name="btn1" value="apply" onclick="applyInput();">&nbsp;<input type="button" name="btn1" value="close" onclick="closeInput();">
</form>

</div>
<!--end_edit_menu-->
<p>This is an editable paragraph</p>
<br>
<a href="myPage.html">This is an editable link</a>
<div>This is an editable div</div>
<br>
<a href="myPage.html">This is another editable link</a>
</body>
</html>

roxyroolz
Aug 15th, 2005, 03:36 PM
Thanks all of you for your help!

Exams over, I am back with my pet project. Had some time to work with the script Martin posted...

Isn't it a little inefficient.. I mean for each point if one continues to create a DIV tag... it will for sure lead to a lot of lag as it does so on my PIVm system... :(

Is there possibly a way to optimize the performance so that the curve is unbroken and there is not so much of a lag... all of this without extending the browser i.e.

Thanks in advance!

~R~

martin_narg
Aug 15th, 2005, 04:01 PM
yep, it's definately not the best way to go about it - SVG and VML are much better =)

m_n

roxyroolz
Aug 17th, 2005, 10:21 PM
Thanks martin for your reply... but the prob is I wanted to make something like a browser independent solution.. would it not be possible with this`? Without extending the browser somehow? Like the Vectorgraphics library by walter zorn, who has combined several pixels in a DIV tag... Well, seems it will be a pipe dream.. : (