I'm making a Force Directed Graph of semanticproxy.com data using this arbor fork. I have a main Explorer object which controls the nodes (following is abbreviated):
function Explorer(canvas) {
// set up particle system
this.ps = arbor.ParticleSystem(1000, 600, 0.5);
this.ps.renderer = Renderer(canvas);
this.canvas = $(canvas).get(0);
var self = this;
$('body').bind('subjectFound', function(event, sourceNode, targetName, targetRelevance) {
self.addEdge(sourceNode, targetName, targetRelevance);
});
}
Explorer.prototype.addEdge = function(source, target, relevance) {
var target = this.ps.addNode(target);
if (source != target) this.ps.addEdge(source, target, {relevance:relevance});
}
// start the explorer up on a new subject
Explorer.prototype.start = function(name) {
var node = this.ps.addNode(name);
node.populate(this.ps);
};
var xplor = new Explorer("#viewport");
xplor.start("Andreas Michl");
You'll notice that the start() method adds a node to the particle system (works great), and then populates that node. Here's the code for the node, in part (please note that I'm augmenting the arbor.js Node prototype):
// fills this node with data from SemanticProxy
Node.prototype.populate = function() {
var self = this;
// get the semantic data for this subject
// setup the handler function
var functionName = "subjectHandler" + new Date().getTime();
window[functionName] = function(data) {
// invoke function with saved context and parameter
self._fillFromSP.call(self, data);
}
var url = "http://service.semanticproxy.com/processurl/"+SP_KEY+"/jsonp:"+functionName+"/http://en.wikipedia.org/wiki/"+this.name;
$.ajax({url: url, dataType: "script", type: "GET", cache: false, callback: null, data: null});
};
// fills this subject with data from SemanticProxy
Node.prototype._fillFromSP = function(data) {
var self = this;
$.开发者_如何学JAVAeach(data, function(key, val) {
if (key != "doc") {
if (val.name && val.relevance) {
$('body').triggerHandler('subjectFound', [self, val.name, val.relevance]);
}
}
});
}
So once the semanticproxy data is returned it should trigger the 'subjectFound' handler in the Explorer object and add a node, just like it did before with the first node. But it chokes every time - the diagram locks up and the usage on one of my cpu cores hits 100% (Firefox and Chrome).
However, if I change the populate method to the following, it works fine:
Node.prototype.populate = function() {
var self = this;
// get the semantic data for this subject
// setup the handler function
var functionName = "subjectHandler" + new Date().getTime();
window[functionName] = function(data) {
// invoke function with saved context and parameter
self._fillFromSP.call(self, data);
}
window[functionName](json);
};
var json = {"doc":{"info" ... "length":48}]}};
where the json variable holds the data from the very same semanticproxy URL as before. All the relevant nodes appear and render beautifully. So it's only when I use the $.ajax call, and it's only when the data actually get's back to my browser that it locks up. I can step through the code and it calls the $('body').triggerHandler with the correct parameters the correct number of times. It successfully triggers everything to the Explorer.addEdge() call where the arbor particle system is told to add some nodes - and that's when it doesn't work. But only when using the AJAX call!
Any ideas? Thanks in advance.
Update: I just set up a little Rails controller to use as a proxy. No luck either. Instead of the $.ajax call and the weird window handler, in the populate method I just did a straight:
var url = "http://localhost:3000/?url=http://service.semanticproxy.com/processurl/8bv73k5hgj9prkhee9rrr9s4/json/http://en.wikipedia.org/wiki/Andreas_Michl";
$.getJSON(url, function(data) {
self._fillFromSP(data);
});
But that had the same behaviour - lock-up. Maybe a race condition or something else in the arbor code?
Solution
The populate method now reads:
// fills this node with data from Wikipedia and SemanticProxy
Node.prototype.populate = function() {
var self = this;
// get the semantic data for this subject
var ajaxWorker = new Worker('javascripts/worker_ajax.js');
ajaxWorker.onmessage = function(event) {
self._fillFromSP(event.data);
};
ajaxWorker.postMessage({name: this.name});
};
and worker_ajax.js is:
onmessage = function(event) {
var SP_KEY = "xxxx";
var url = "http://service.semanticproxy.com/processurl/"+SP_KEY+"/jsonp:handle/http://en.wikipedia.org/wiki/"+event.data.name;
importScripts(url);
}
var handle = function(json) {
postMessage(json);
}
WebWorkers and JSONP don't go together, because WebWorkers have no DOM to attach elements to, in other words you cannot attach your script tag to anywhere.
Read this article for a possible work-around: http://cggallant.blogspot.com/2010/10/jsonp-overview-and-jsonp-in-html-5-web.html
As for using JQuery in Webworkers, take a look at this topic: HTML Web Worker and Jquery Ajax call
精彩评论