为WebWorker设置正确的路径

WebWorker的路径通常是写在代码源文件中,而且这个路径并非其相对父js文件的相对路径,而似乎是相对页面的路径。所以指定一个正确的可随处部署的路径变得有些麻烦。昨天有人给HeatCanvas提了这个问题我才想到上网搜索了一下,有一个还算挺不错的办法。

写一个getPath函数,从document里找到父js的路径,拼到Worker的名字上。对heatcanvas.js这个文件来说就是:

HeatCanvas.getPath = function() {
    var scriptTags = document.getElementsByTagName("script");
    for (var i=0; i<scriptTags.length; i++) {
        var src = scriptTags[i].src;
        var pos = src.indexOf("heatcanvas.js");
        if (pos > 0) {
            return src.substring(0, pos);
        }
    }
    return "";
};

因此现在HeatCanvas已经解决了这个路径问题,现在这个库应该更好用了。当然如果你改了我的文件名我就无话可说了。

HeatCanvas performance enhanced

heatcanvas

时隔半年日日沉浸在clojure世界里的时候,多亏了github上Daniel Azuma的提示,现在HeatCanvas通过Image Data数组来绘制图像。过去由于不太熟悉Canvas API,我用的是fillRect来填充1像素大小的区域,模拟像素的渲染。但是这种方式导致浏览器渲染的效率非常低。

ImageDataArray允许用户开辟一个固定大小的buffer,并设置每一像素的像素值,然后一次性地渲染到canvas上。详情可以参考这里:Pixel manipulation with canvas

这次性能的提升基本没有影响API,唯一的区别是如果原先自定义了value-color的映射函数的话,现在不再接受hsl的css字符串了,新的API需要你返回一个四个元素的数组,分别代表h, s, l, a,值域[0-1]。

感谢关注HeatCanvas的朋友。

Roar for mootools 1.4

早在天下大势还处在分久必合的时候,那时候mootools还有不少简单实用的小库,比如我今天搜索”mootools notification”就找到这个08年的库叫做Roar。不过遗憾的是从那以后,这个库就再也没有更新过了。

Mootools本身也沉寂了很久,这个项目恐怕也要思考自己未来的发展方向了。今年9月Mootools迈进了1.4,API上有一些变化。现在的下载页也能看到with/without backward compatibility的版本分开下载。为了用上Roar,我尝试了这两个版本发现都不能使用。最后downgrade到1.2可以确定Roar本身在当时是没有什么问题。

这么多年对mootools痴心不改,所以顺手维护了一下Roar,现在可以在1.4 without compatibility的发布下运行了。主要是几个小修改,大多是一些多年deprecated函数被正式删除:

  • Type常量,原先的String.type,Object.type现在统一到一个Type对象下,变成Type.isString和Type.isObject
  • $empty 常量被删除了,现在直接用function()或Function.from()代替
  • $pick 方法被Array.pick取代,参数现在也必须接受数组类型了
  • $merge 方法被Object.merge取代
  • $type 被typeOf取代
  • 函数对象的create方法被删除了,现在可以用函数对象的bind方法替代
  • Browser.Engine 被删除了,需要用其他Browser的API替代

修改后的Roar,放在这个gist里,测试过可以在firefox和chromium上健康使用。IE没有做测试。这个08年的库,眼看四年过去了,用起来依然不错。

作为mootools的铁杆,我还是会一直专一地坚守下去的。(于是,我也已经变成了多年前那些我眼中为旧事物顽抗到底的老家伙了)

Using Google closure library with ClojureScript

Google closure library is shipped with ClojureScript, and could be compiled with ClojureScript into a minimized javascript file. So closure library is doubtlessly the first candidate when you are considering to use an external Javascript library in your cljs browser application.

However, different from clojure’s interoperability with Java, ClojureScript has its own characteristics when you are interoperating with JavaScript and JavaScript based libraries.

Clojure types are not fully compatible with JavaScript types
In ClojureScript, you can never treat a Clojure map as a JavaScript object although they have similar characteristics. You have to do some conversion before passing a clojure map to javascript functions. Matthew Gilliard made a sample of such conversion.

JavaScript package is not Clojure namespace
This could be a common mistake for ClojureScript newbie. Actually, JavaScript doesn’t have concept of “Package” or “Namespace”. Many JavaScript libraries(dojo, Google Closure) made enhancement on this. ClojureScript also takes advantage of this mechanism. So before you start to coding with closure, you may browse closure library API document, and find a module called goog.net which includes lots of types. Then you write this:

(ns myjs
  (:require [goog.net :as gnet]))

But compiler shows you “ERROR: JSC_MISSING_PROVIDE_ERROR. required “goog.net” namespace never
provided at … “. This is not a PATH issue. The root cause is that closure module has a lower granularity than Clojure ones. Types are often contained in their own modules. You can find closure source code in clojurescript/closure/library/closure. Modules are declare with goog.provide function. Thus, you should require this name instead of the logical module name.

(ns myjs
  (:require [goog.net.XhrIo :as gxhr]))

In addition, ClojureScript does not support ‘use’.

Just use full name for JavaScript class
For functions contains in some module, you can refer it with the clojure way:

(ns myjs
  (:require [goog.dom :as dom]))
(dom/$ "element-id")

But for classes, just use the full name and ignore the module alias.

(ns myjs
  (:require [goog.net.XhrIo :as gxhr]))
(def xhr (goog.net.XhrIo.))

These are basic tips before you start using Closure with ClojureScript. Leveraging on Google’s closure library, you can create cross-browser JavaScript application with Clojure easily.

HeatCanvas support for Leaflet

Leaflet is a light weight web mapping library developed by Cloudmade. Leaflet is designed for compatibility with both desktop browser and mobile browser.

HeatCanvas-Leaflet extension enables heat map on Leaflet. You can create heat map layer and add it to Leatlet map:

var heatmap = new L.TileLayer.HeatCanvas("Heat Canvas", map, {},
                        {'step':0.3, 'degree':HeatCanvas.QUAD, 'opacity':0.7});
heatmap.pushData(32.1104, 118.0852, 14);
//push more data ...
map.addLayer(heatmap);

You can find live demo on:
http://sunng87.github.com/heatcanvas/leaflet.html
Mobile browser is also supported. (Tested on Firefox Android and default Android browser)

Find more about HeatCanvas on github page.

Leaflet is still buggy for extension. There is a latlng-pixel coordinate conversion issue in low zoom level, affects this demo. Hope it could be fixed soon.