I'm plotting a few hundred thousand points via MarkerClustererPlus, and I want to set groups of cluster icons (colour) based on some exteral property (not based on number of markers represented).
The only way I can think to do this is by creating multiple MarkerClusterer objects and passing in a different options
object, but I feel like I'll take a big performance hit doing that. Is there a better way?
Given the image above, I'd like 139, 24, and 5 to be yellow and 213, 25, 30, and 2 to be red; and if possible, update their styles/options via setOptions:mc.group[0].setOptions({"url": imgPath +lookupThreshold(severity)+ '.svg' });
mc.group[1].setOptions({"url": imgPath +lookupThreshold(severity)+ '.svg' });
P.S. If anyone is interested, I tweaked the lib so the cluster icon scales to its size† by supplying an svg image and increasing the width & height in the options object:
var mcOptions = {
"styles": [{
"height": 19,
"url": img/map/clusters/",
"width": 19
},{
"height": 24,
"url": img/map/clusters/",
"width": 24
}, {…}]
};
for ( var s = mcOptions.styles.length-1; s >= 0; s-- )
{ mcOptions.styles[s].url += lookupThreshold(severity) + '.svg'; }
// lookupThreshold switches severity and returns a string: red, orange, …
Then added the following to markerclusterer.js
:
line 275: this.backgroundSize_ = style.backgroundSize || "contain";
line 300: style.push('background-size:' + this.backgroundSize_ + ';');
† Works in Ffx 19.0.2, Chrome 26.x, Chrome Canary 28.x, Safari 6.0.2, IE 9.0.8 (but not Opera 12.15).
EDIT It seems there is not much of a performance hit from creating multiple instances of MarkerClusterer; however, it appears that the properties/options object passed to MC is shared amoung the instances of MCs.
Solved I had to modify the MarkerClustererPlus library near line 665 to clone opt_options
(the lib was using a reference, which caused all previous opt_options to be overwritten with the newest/last one passed).
So it turns out the trouble was coming from the MarkerClustererPlus lib itself:
656: function MarkerClusterer(map, opt_markers, opt_options) {
…
665: opt_options = opt_options || {};
Line 665 creates a reference to the existing object, instead of a new copy. I couldn't use MarkerClusterer.prototype.extend
from line 1539 because it does not make a deep copy (and it extends only an object's prototype).
So, I wrote my own deep-copy function (jsfiddle), which I made globally available (rather than add it to the prototypes of both Array and Object):
function deepCopy(obj) {
this.cloneArr = function (arr) {
var newArr = [];
for ( var i = arr.length-1; i >= 0; i-- ) newArr[i] = this.evalObj( arr[i] );
return newArr;
};
this.cloneObj = function(obj) {
var newObj = {};
for ( var prop in obj ) newObj[prop] = this.evalObj( obj[prop] );
return newObj;
};
this.evalObj = function(obj) {
switch ( typeof obj ) {
case 'object':
if ( Array.isArray( obj ) ) return this.cloneArr( obj );
if ( obj instanceof Date === false ) return this.cloneObj( obj );
// pass thru dates, strings, numbers, booleans, and functions
default: return obj; // primitive
}
};
return this.evalObj(obj);
}
I then altered MarkerClustererPlus.js to the following:
656: function MarkerClusterer(map, opt_markers, opt_optionsG) {
…
665: var opt_options = deepCopy( opt_optionsG ) || {};
I tested having 5 instances of MarkerClustererPlus (each with 5000 markers, 25000 total), and there was no decernable performance impact compared to having a single MC+ instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With