<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Javascript on David Hamp-Gonsalves</title><link>https://davidhampgonsalves.com/tags/javascript/</link><description>Recent content in Javascript on David Hamp-Gonsalves</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Sat, 15 Mar 2014 00:00:00 +0000</lastBuildDate><atom:link href="https://davidhampgonsalves.com/tags/javascript/index.xml" rel="self" type="application/rss+xml"/><item><title>Dynamic CSS Reset</title><link>https://davidhampgonsalves.com/dynamic-css-reset/</link><pubDate>Sat, 15 Mar 2014 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/dynamic-css-reset/</guid><description>&lt;p&gt;When ever you ever have to inject HTML into an unknown page you have to battle with all the page styles messing with your own content. This happens a lot when building bookmarklets like my recent &lt;a href="https://davidhampgonsalves.com/spritz-like-rsvp-reader-bookmarklet/"&gt;RSVP Reader&lt;/a&gt;. In the past you had to manually assign values for all the CSS properties that could have been set by the page. Since then then &lt;em&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/initial"&gt;initial&lt;/a&gt;&lt;/em&gt; CSS property was added we can perform this reset automatically. The following is a function that resets all CSS properties for a given DOM node.&lt;/p&gt;</description></item><item><title>Spritz like(RSVP) Reader Bookmarklet</title><link>https://davidhampgonsalves.com/spritz-likersvp-reader-bookmarklet/</link><pubDate>Tue, 04 Mar 2014 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/spritz-likersvp-reader-bookmarklet/</guid><description>&lt;p&gt;So after seeing &lt;a href="http://www.spritzinc.com/"&gt;Spritz&lt;/a&gt; I waited for someone to whip up a nice extension so that I could try out the same technique(&lt;a href="http://en.wikipedia.org/wiki/Rapid_Serial_Visual_Presentation"&gt;RSVP&lt;/a&gt;) in my brower. Since that hasn&amp;rsquo;t happened I created a bookmarklet that covers the basics so that we test this all out in real life and see how useful it really is.&lt;/p&gt;
&lt;h2 id="install"&gt;install&lt;/h2&gt;
&lt;p&gt;To install drag the following link to your bookmark bar.&lt;/p&gt;
&lt;pre&gt;

&lt;a href="javascript\:(function() { var text = getSelectedText(); if(!text) { /* TODO\: send page to api to get only content and then read that */ /*https\://app.embed.ly*/ alert('please select some text to read.'); return; } var model = { index \: 0, lastTextChange \: new Date().getTime() - 99999999, baseInterval \: 60000 / 500 }; setupMainContainer(model); setupKeyboardControl(model); updateWPM(model); model.words = getWords(text); read.apply(model); function setupKeyboardControl(model) { document.onkeydown = function(e) { var key = e.keyCode; /* treat up and down arrows like +/- */ if(key === 38) key = 187; else if(key === 40) key = 189; var noAction = false; switch (key) { case 27\: finish(model); break; case 32\: /*spacebar pauses reading*/ model.pause = !model.pause; break; case 37\: /* jump back 20 words and then draw a single frame if paused */ model.index = model.index &gt; 20 ? model.index-20 \: 0; if(model.pause) read.apply(model, [null, true]); break; case 39\: /* jump forward 20 words and then draw a single frame if paused */ model.index += 20; if(model.index &gt;= model.words.length) model.index = model.words.length-1; if(model.pause) read.apply(model, [null, true]); break; case 82\: /*toggle rewind when 'r' is pressed*/ model.rewind = true; model.pause = false; break; case 187\: model.baseInterval = 60000 / ((60000 / model.baseInterval) + 5); updateWPM(model); break; case 189\: model.baseInterval = 60000 / ((60000 / model.baseInterval) - 5); updateWPM(model); break; default\: noAction = true; }; /* disable key propigation if its a command key */ if(!noAction) e.preventDefault(); }; document.onkeyup = function(e) { switch (e.keyCode) { case 82\: model.rewind = false; }; }; } function finish(model) { window.cancelAnimationFrame(model.nextAnimation); if(model &amp;&amp; model.container &amp;&amp; model.container.parentNode) model.container.parentNode.removeChild(model.container); } function updateWPM(model, baseInterval) { if(!baseInterval) baseInterval = model.baseInterval; model.wpmContainer.innerHTML = Math.floor(60000 / baseInterval) + 'wpm'; }; function getWords(text) { return text.split(/[\s]+/g).filter(nonEmpty); }; function splitWord(word) { if(word.length === 1) return ['', word, '']; var pivot = 1; switch (word.length) { case 0\: case 1\: pivot = 0; break; case 2\: case 3\: case 4\: case 5\: pivot = 1; break; case 6\: case 7\: case 8\: case 9\: pivot = 2; break; case 10\: case 11\: case 12\: case 13\: pivot = 3; break; default\: pivot = 4; }; return [word.substring(0,pivot), word.substring(pivot, pivot+1), word.substring(pivot+1)]; }; function nonEmpty(x) { return x.length &gt; 0; }; function read(time, isSingleFrame) { var now = new Date().getTime(); if(!isSingleFrame &amp;&amp; ((new Date().getTime() - this.lastTextChange) &lt; this.nextInterval || model.pause)) { this.nextAnimation = window.requestAnimationFrame(read.bind(this)); return; } var word = this.words[this.index]; var wordParts = splitWord(word); var center = this.canvas.width / 2; var charWidth = this.canvasContext.measureText(wordParts[1]).width; var vAlign = this.canvas.height / 2; this.canvasContext.clearRect (0, 0, this.canvas.width, this.canvas.height); this.canvasContext.fillStyle = 'black'; this.canvasContext.textAlign = 'right'; this.canvasContext.fillText(wordParts[0], center - (charWidth/2), vAlign); this.canvasContext.textAlign = 'center'; this.canvasContext.fillStyle = 'red'; this.canvasContext.fillText(wordParts[1], center, vAlign); this.canvasContext.fillStyle = 'black'; this.canvasContext.textAlign = 'left'; this.canvasContext.fillText(wordParts[2], center + (charWidth/2), vAlign); if(!this.rewind) { if((this.index + 1) &lt; this.words.length) this.index += 1; } else if(this.index &gt; 0) this.index -= 1; this.lastTextChange = now; /* this should be moved to a different structure that runs all the rules and only builds the regex once */ if(this.index &lt; 5) { this.nextInterval = this.baseInterval * (5 - this.index); } else if(/.[^a-zA-Z\d\s\:]./.test(word)) { /* slow down for weird(special chars) words */ this.nextInterval = this.baseInterval * 1.3; } else if(word.length &gt; 7) { /* slow down for longer words */ this.nextInterval = this.baseInterval * 1.1; } else if(/^[^a-zA-Z\d\s\:]/.test(word)) { /* slow down for beginning of quote or pharagraph or werid chars */ this.nextInterval = this.baseInterval * 1.3; } else if(/[^a-zA-Z\d\s\:]$/.test(word)) { this.nextInterval = this.baseInterval * 1.3; } else { this.nextInterval = this.baseInterval; } console.log(this.nextInterval); if(!isSingleFrame) this.nextAnimation = window.requestAnimationFrame(read.bind(this)); }; function applyStylesToNode(node, styles) { resetStyles(node); /*TODO\: add base reset styles first*/ for(var attr in styles) { node.style[attr]=styles[attr]; } }; function resetStyles(node) { if(!node) console.error('node was invalid\: ' + node); /*reset all css*/ var props = window.getComputedStyle(node, null); for(var i=0, len=props.length ; i &lt; len ; i++) { node.style[props] = 'initial'; } }; function getSelectedText() { var html = null; if (typeof window.getSelection != 'undefined') { var sel = window.getSelection(); if (sel.rangeCount) { var container = document.createElement('div'); for (var i = 0, len = sel.rangeCount; i &lt; len; ++i) { container.appendChild(sel.getRangeAt(i).cloneContents()); } html = container.innerHTML; } } else if (typeof document.selection != 'undefined') { if (document.selection.type == 'Text') { html = document.selection.createRange().htmlText; } } var tmp = document.createElement('DIV'); tmp.innerHTML = html; return tmp.textContent || tmp.innerText; }; function setupMainContainer(model) { var container = document.getElementById('davidhampgonsalves-container-1234kj1;2l3k4j'); /* remove lost containers(caused by clicking bookmarklet multiple times) */ if(container) { if(container.parentNode) container.parentNode.removeChild(container); } container = document.createElement('div'); container.setAttribute('id', 'davidhampgonsalves-container-1234kj1;2l3k4j'); var styles = {position\:'fixed', display\:'table', border\: '20px solid #333', background\:'#EEE', width\: '400px', height\:'150px', top\:'50%', left\:'50%', 'margin-top'\:'-100px', 'margin-left'\:'-150px', 'font-family'\:'Arial', 'font-size'\:'15px', 'text-align'\: 'center', 'z-index' \: '9999999999999999999' }; applyStylesToNode(container, styles); var wordContainer = document.createElement('canvas'); applyStylesToNode(wordContainer, {height\: '150px', width\:'300px'}); model.canvas = wordContainer; model.canvasContext = wordContainer.getContext('2d'); model.canvasContext.font='30px Georgia'; model.wpmContainer = document.createElement('div'); applyStylesToNode(model.wpmContainer, {margin\:'10px', 'text-align'\:'left', width\:'100px', position\:'absolute', bottom\:'0', left\:'0'}); var aboutLink = document.createElement('a'); aboutLink.appendChild(document.createTextNode('?')); aboutLink.href='http\://www.davidhampgonsalves.com/spritz-like-rsvp-reader-bookmarklet/'; aboutLink.target='_blank'; applyStylesToNode(aboutLink, {margin\:'10px', 'text-align'\:'right', width\:'100px', position\:'absolute', bottom\:'0', right\:'0', 'text-decoration'\: 'none'}); container.appendChild(wordContainer); container.appendChild(model.wpmContainer); container.appendChild(aboutLink); document.body.appendChild(container); model.container = container; };}());"&gt;RSVP&lt;/a&gt;

&lt;/pre&gt;
&lt;h2 id="instructions"&gt;Instructions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Select some text on a page and click the bookmarklet.&lt;/li&gt;
&lt;li&gt;Read like the wind!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="key-bindings"&gt;Key Bindings&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ESC&lt;/strong&gt;: exit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R(hold)&lt;/strong&gt;: rewind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;←/→&lt;/strong&gt;: jump forward or back by 20 words.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-/+&lt;/strong&gt; or &lt;strong&gt;↑/↓&lt;/strong&gt;: adjust WPM rate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spacebar&lt;/strong&gt;: pause/resume.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="features"&gt;Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Smooth acceleration on start up.&lt;/li&gt;
&lt;li&gt;Variable speed when reading long words, punctuation, etc.&lt;/li&gt;
&lt;li&gt;Spritz like word centering.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="notes"&gt;Notes&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m sure Spritz is way better then this simple bookmarklet. This isn&amp;rsquo;t a comment on how easy this technology is. To do it properly it would take a look of statistics and reading analysis and a lot of science which I think is what Spritz has done. This is just a very basic tool that I built to try out the concept of RSVP and see how useful it is.&lt;/p&gt;</description></item><item><title>Compressing JSON into a Brittle Lightweight String</title><link>https://davidhampgonsalves.com/compressing-json-into-a-brittle-lightweight-string/</link><pubDate>Thu, 07 Nov 2013 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/compressing-json-into-a-brittle-lightweight-string/</guid><description>&lt;p&gt;Client side single page apps tend to throw a lot of JSON data across the internet. These are some techniques I used on &lt;a href="http://crimeheatmap.ca"&gt;cimrheatmap.ca&lt;/a&gt; to compress my Geo/Time data by about &lt;strong&gt;90%&lt;/strong&gt; and avoided the overhead of gzipping the page. Be warned most of this was just for fun and is a silly idea because of the disadvantages listed bellow.
&lt;code&gt;{lat\:45.123, lng\:-63.123, type\: 'Assult', timestamp\: '1383837388112'}&lt;/code&gt; vs. &lt;code&gt;'3 0 '&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="maps-vs-arrays"&gt;Maps vs. Arrays&lt;/h2&gt;
&lt;p&gt;Standard JSON compression usually focuses on flatening the maps that are normally used to represent objects. This removes all the duplciate keys.&lt;/p&gt;</description></item><item><title>Animated Javascript Heatmaps.js</title><link>https://davidhampgonsalves.com/animated-javascript-heatmaps.js/</link><pubDate>Wed, 23 Oct 2013 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/animated-javascript-heatmaps.js/</guid><description>&lt;p&gt;I&amp;rsquo;ve been working on a &lt;a href="http://www.crimeheatmap.ca"&gt;crime heatmap animation&lt;/a&gt; lately and these are some tips for anyone else building something similar.&lt;/p&gt;
&lt;h2 id="heatmapjs"&gt;Heatmap.js&lt;/h2&gt;
&lt;p&gt;For my animation I used a version of &lt;a href="https://github.com/pa7/heatmap.js/pull/35"&gt;heatmap.js&lt;/a&gt; that was tweeked for animation by &lt;a href="http://alastair.is/"&gt;alastair.is&lt;/a&gt;. The tweek slightly changes the look of the heatmaps but achieves a much better frame rate.&lt;/p&gt;
&lt;h2 id="the-animation"&gt;The Animation&lt;/h2&gt;
&lt;p&gt;If you new to Javascript based animation you will want to read up on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame"&gt;window.requestNextAnimationFrame()&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For a heatmap animation you need to push the current set of geo coardinates to the heatmap which corrispond with the the current animation progress.&lt;/p&gt;</description></item><item><title>Detecting Mobile Device from Javascript</title><link>https://davidhampgonsalves.com/detecting-mobile-device-from-javascript/</link><pubDate>Mon, 21 Oct 2013 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/detecting-mobile-device-from-javascript/</guid><description>&lt;p&gt;This is a pretty lightweight way of detecting when your javascript is living in a mobile device.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;orientation&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;undefined&amp;#39;&lt;/span&gt;) { &lt;span style="color:#75715e"&gt;/* put mobile spesific code here */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To omit spesific devices from running this code you can also add individual checks like the following.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;typeof&lt;/span&gt; window.&lt;span style="color:#a6e22e"&gt;orientation&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;undefined&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;!&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;userAgent&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;match&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;/iPad/i&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* put mobile spesific(but not ipad) code here */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is a mix of the answers found on &lt;a href="http://stackoverflow.com/questions/11381673/javascript-solution-to-detect-mobile-browser"&gt;stack overflow&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Drawing Region Polygons on Google Maps API v.3</title><link>https://davidhampgonsalves.com/drawing-region-polygons-on-google-maps-api-v.3/</link><pubDate>Tue, 06 Aug 2013 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/drawing-region-polygons-on-google-maps-api-v.3/</guid><description>&lt;p&gt;You can &amp;ldquo;draw&amp;rdquo; all sorts of stuff on Google Maps using Layers but mor simply you can also directly create polygons and with a bit of extra work make them looks pretty cool. In this case I&amp;rsquo;m tracing a country using data from the &lt;a href="https://www.google.com/fusiontables/DataSource?docid=1UGwYogqtxVPga_76rxpL38CO1U6tr2s6Z0wSaQ"&gt;Natural Earth Google Fusion Tables Dataset&lt;/a&gt;. Here is the final product showing &lt;a href="http://www.iswhere.us/new_york.html"&gt;where New York is&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="drawing-a-polygon"&gt;Drawing a Polygon&lt;/h2&gt;
&lt;p&gt;The Natural Earth Dataset provides outline coordinates using the EPSG 4326 projection. We can build our polygon(s) with those points like:&lt;/p&gt;</description></item><item><title>Generating Bitcoins using Online Ads</title><link>https://davidhampgonsalves.com/generating-bitcoins-using-online-ads/</link><pubDate>Fri, 02 Aug 2013 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/generating-bitcoins-using-online-ads/</guid><description>&lt;p&gt;After reading about using &lt;a href="http://threatpost.com/buy-an-ad-own-a-browser-botnet"&gt;online ads to launch a javascript based DDoS attack&lt;/a&gt; I started wondering about how well such a system would do at mining bitcoins. These are my &lt;em&gt;rough calculations.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;From my research I&amp;rsquo;ve found there are 3 ways to mine bitcoins(compute hashes) using Javascript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;UI thread&lt;/em&gt; (I was seeing about 800 hashes/s)&lt;/li&gt;
&lt;li&gt;Multiple threads via &lt;em&gt;WebWorkers&lt;/em&gt; (I was seeing about 13000 hashes/s)&lt;/li&gt;
&lt;li&gt;Using the GPU via &lt;em&gt;WebGL&lt;/em&gt; (&lt;a href="http://caniuse.com/webgl"&gt;limited browser support&lt;/a&gt; couldn&amp;rsquo;t find working example).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;I based my numbers on this implementation:&lt;/em&gt; (http://bitcoin.biniok.net/gl.html) running chrome on a pentium 4. The rates are averages over 5 seconds.&lt;/p&gt;</description></item><item><title>Javascript Damerau Levenshtein Algorithim</title><link>https://davidhampgonsalves.com/javascript-damerau-levenshtein-algorithim/</link><pubDate>Tue, 20 Nov 2012 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/javascript-damerau-levenshtein-algorithim/</guid><description>&lt;p&gt;The &lt;a href="http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance"&gt;Damerau Levenshtein&lt;/a&gt; algorithim calculates a distance between two words in the same way that basic Levenshtein does but adds transpositions to the set of operations that it uses to calculate distance. This makes it much more reliable at finding similiar or alternate spellings of words.&lt;/p&gt;
&lt;p&gt;I was doing some nodejs work lately and needed such a function to clean up one of my datasets and so I ported this version from C# to Javascript.&lt;/p&gt;</description></item><item><title>HTML Sticky Headers</title><link>https://davidhampgonsalves.com/html-sticky-headers/</link><pubDate>Sun, 22 Jan 2012 00:00:00 +0000</pubDate><guid>https://davidhampgonsalves.com/html-sticky-headers/</guid><description>&lt;p&gt;Sticky headers are heading elements that stick to the top of the window as the user scrolls down the page. This is useful since you can use them to retain the contextual information of the section regardless of the position.&lt;/p&gt;
&lt;p&gt;In my case I needed to have multiple headers in the hourly forecast list for &lt;a href="http://www.hourweather.com/"&gt;hourweather.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I found there wasn&amp;rsquo;t much out there about this topic, especially when you want to have multiple sticky headers per page so I thought I&amp;rsquo;d share my implementation(which is pretty rough) for others to reference for the main ideas.&lt;/p&gt;</description></item></channel></rss>