{"id":199,"date":"2008-04-14T17:00:49","date_gmt":"2008-04-14T21:00:49","guid":{"rendered":"http:\/\/benjamin.smedbergs.us\/blog\/2008-04-14\/hgweb-viewer-canvas-version\/"},"modified":"2008-04-14T17:09:00","modified_gmt":"2008-04-14T21:09:00","slug":"hgweb-viewer-canvas-version","status":"publish","type":"post","link":"http:\/\/benjamin.smedbergs.us\/blog\/2008-04-14\/hgweb-viewer-canvas-version\/","title":{"rendered":"hgweb viewer, canvas version"},"content":{"rendered":"<p>If you want to go drawing complex graphics on the web, you have two basic options: <a href=\"http:\/\/developer.mozilla.org\/en\/docs\/SVG\">SVG<\/a> and the <a href=\"http:\/\/developer.mozilla.org\/en\/docs\/HTML:Canvas\">HTML canvas element<\/a>.<\/p>\n<p>My <a href=\"http:\/\/benjamin.smedbergs.us\/blog\/2008-03-26\/wandering-around-mercurial-repositories\/\">first attempt<\/a> at the hgweb graphical browser used SVG. Actually, it used an unholy hybrid of SVG and HTML: the revisions themselves were drawn using absolutely positioned HTML. The arrows between the boxes were drawn using SVG. I did this for several reasons:<\/p>\n<ul>\n<li>only Firefox supports drawing text into canvas elements\n<li>I could use DOM events to do hit-testing and navigation\n<li>you can select\/copy\/paste text in HTML\n<\/ul>\n<p>Unfortunately, the performance of the first version was not very good, and the code was very complex. I was maintaining several parallel data structures: a JS object graph, and the DOM objects for revisions and arrows. The bookkeeping code to keep data in sync was dwarfing the actual layout logic.<\/p>\n<p>Instead I decided to try using canvas. Sucking out the bookkeeping code and replacing it with a custom drawing code turned out to be much easier than I expected. Now all of the data is kept in a single tree, and layout, rendering, and hit-testing are all blazingly fast.<\/p>\n<p>After getting it basically working, I was able to add additional features in a matter of minutes:<\/p>\n<ul>\n<li>Collision detection\n<li>Animation when navigating between revisions\n<li>Switched to a vertical layout which provides more information\n<li>Made arrows into curves\n<li>Highlight the &#8220;center&#8221; node\n<\/ul>\n<p>The disadvantages of this approach are unfortunate:<\/p>\n<ul>\n<li>Only works in Firefox 3+ (needs the experimental mozDrawText API)\n<li>Impossible to select or copy text\n<\/ul>\n<p><a href=\"http:\/\/office.smedbergs.us\/viewer\/index.xhtml#mozilla-central:7531959482c7df9a2141b875bb1228365fe0d4e2\">check it out<\/a> (my development machine, so it may go down at any time) or <a href=\"http:\/\/hg.mozilla.org\/users\/bsmedberg_mozilla.com\/hgpoller\/\">get the source<\/a>.<\/p>\n<p>Now I really promise I don&#8217;t have any more time to spend on this project. Contributions welcome!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you want to go drawing complex graphics on the web, you have two basic options: SVG and the HTML canvas element. My first attempt at the hgweb graphical browser used SVG. Actually, it used an unholy hybrid of SVG and HTML: the revisions themselves were drawn using absolutely positioned HTML. The arrows between the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[94,93,41,95,77],"class_list":["post-199","post","type-post","status-publish","format-standard","hentry","category-untagged","tag-canvas","tag-hgweb","tag-mercurial","tag-mozdrawtext","tag-svg"],"_links":{"self":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/posts\/199","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/comments?post=199"}],"version-history":[{"count":0,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/posts\/199\/revisions"}],"wp:attachment":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/media?parent=199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/categories?post=199"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/tags?post=199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}