Model-Atlas / js /sigma /sigma.parseJson.js
Eliahu's picture
Added handling of gzipped data in safari
932fbc6
// // Scott Hale (Oxford Internet Institute)
// // Requires sigma.js and jquery to be loaded
// // based on parseGexf from Mathieu Jacomy @ Sciences Po M�dialab & WebAtlas
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
// Regular implementation for Chrome and other browsers
sigma.publicPrototype.parseJson = function(gzippedJsonPath, callback) {
var sigmaInstance = this;
// Use XMLHttpRequest for binary data
var xhr = new XMLHttpRequest();
xhr.open('GET', gzippedJsonPath, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
if (xhr.status === 200) {
try {
// Decompress the gzipped data using pako
var inflatedData = pako.inflate(new Uint8Array(xhr.response));
// Convert binary data to string
var jsonString = new TextDecoder('utf-8').decode(inflatedData);
// Parse the JSON
var jsonData = JSON.parse(jsonString);
// Process nodes
for (var i = 0; i < jsonData.nodes.length; i++) {
var id = jsonData.nodes[i].id;
sigmaInstance.addNode(id, jsonData.nodes[i]);
}
// Process edges
for (var j = 0; j < jsonData.edges.length; j++) {
var edgeNode = jsonData.edges[j];
var source = edgeNode.source;
var target = edgeNode.target;
var label = edgeNode.label;
var eid = edgeNode.id;
sigmaInstance.addEdge(eid, source, target, edgeNode);
}
// Call the callback function if provided
if (callback) {
callback.call(sigmaInstance);
}
} catch (error) {
console.error("Error processing gzipped JSON:", error);
}
} else {
console.error("Error fetching gzipped JSON. Status:", xhr.status);
}
};
xhr.onerror = function() {
console.error("Network error while fetching gzipped JSON");
};
xhr.send();
};
// Create a new function specifically for loading gzipped data safely
// This avoids sigma initialization issues by loading data first
var loadGzippedGraphData = function(gzippedJsonPath, callback) {
// Use XMLHttpRequest for binary data
var xhr = new XMLHttpRequest();
xhr.open('GET', gzippedJsonPath, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
if (xhr.status === 200) {
try {
// Decompress the gzipped data using pako
var inflatedData = pako.inflate(new Uint8Array(xhr.response));
// Convert binary data to string
var jsonString;
try {
jsonString = new TextDecoder('utf-8').decode(inflatedData);
} catch (e) {
// Fallback for older browsers
jsonString = "";
var array = inflatedData;
var i = 0, len = array.length;
var c, char2, char3;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
jsonString += String.fromCharCode(c);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = array[i++];
jsonString += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
jsonString += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
}
// Parse the JSON
var jsonData = JSON.parse(jsonString);
// Return the parsed data to the callback
if (callback) {
callback(jsonData);
}
} catch (error) {
console.error("Error processing gzipped JSON:", error);
if (callback) {
callback(null, error);
}
}
} else {
console.error("Error fetching gzipped JSON. Status:", xhr.status);
if (callback) {
callback(null, new Error("HTTP status: " + xhr.status));
}
}
};
xhr.onerror = function() {
console.error("Network error while fetching gzipped JSON");
if (callback) {
callback(null, new Error("Network error"));
}
};
xhr.send();
};
// Safe initialization for Safari
function initSigmaWithGzippedData(containerId, gzippedJsonPath, options, callbackFn) {
// Make options parameter optional
if (typeof options === 'function') {
callbackFn = options;
options = {};
}
options = options || {};
// For Safari, use a completely different approach
if (isSafari) {
// First, load the data
loadGzippedGraphData(gzippedJsonPath, function(data, error) {
if (error || !data) {
console.error("Failed to load graph data:", error);
return;
}
// Wait for DOM to be completely ready
jQuery(document).ready(function() {
// Make sure container is ready with dimensions
var container = document.getElementById(containerId);
if (!container) {
console.error("Container not found:", containerId);
return;
}
// Ensure container has dimensions
if (!container.offsetWidth || !container.offsetHeight) {
container.style.width = container.style.width || "100%";
container.style.height = container.style.height || "500px";
container.style.display = "block";
}
// Wait for next animation frame to ensure DOM updates
requestAnimationFrame(function() {
// Create settings with explicit container reference
var sigmaSettings = Object.assign({}, options);
// Wait a bit more for Safari
setTimeout(function() {
try {
// Initialize sigma with empty graph first
var sigmaInstance = new sigma(containerId);
// Add nodes and edges manually
for (var i = 0; i < data.nodes.length; i++) {
var id = data.nodes[i].id;
sigmaInstance.addNode(id, data.nodes[i]);
}
for (var j = 0; j < data.edges.length; j++) {
var edgeNode = data.edges[j];
var source = edgeNode.source;
var target = edgeNode.target;
var label = edgeNode.label || "";
var eid = edgeNode.id;
sigmaInstance.addEdge(eid, source, target, edgeNode);
}
// Refresh the graph
sigmaInstance.refresh();
// Call user callback if provided
if (callbackFn) {
callbackFn(sigmaInstance);
}
} catch (e) {
console.error("Error initializing sigma:", e);
}
}, 300); // Longer delay for Safari
});
});
});
} else {
// For Chrome and others, use a more standard approach
jQuery(document).ready(function() {
try {
var sigmaInstance = new sigma(containerId);
sigmaInstance.parseGzippedJson(gzippedJsonPath, function() {
this.refresh();
if (callbackFn) callbackFn(this);
});
} catch (e) {
console.error("Error initializing sigma:", e);
}
});
}
}