D3 already features a bunch of symbols, but I'd like to add a custom one. So that I could for example just call d3.svg.symbol().type('custom')
in my code.
This cannot be done directly since the array of symbol definitions is not accessible from the API.
You can see in the source code HERE that the symbol definitions are stored in a d3.map
called d3_svg_symbols
. The only part of this map that gets exposed to the public API is the array of keys. This is done by calling the .keys()
method of the map, HERE.
d3.svg.symbolTypes = d3_svg_symbols.keys();
The definitions themselves are never exposed, and so you cannot add definitions directly as you had hoped.
You can, however, construct a workaround without too much difficulty. One way would be to create a map of your custom symbols, and create a function based on the existing one for the built-in symbols. For example:
// DEFINE A COUPLE OF CUSTOM SYMBOLS
var customSymbolTypes = d3.map({
'custom-symbol-1': function(size) {
// returns a path-data string
},
'custom-symbol-2': function(size) {
// returns a path-data string
}
});
// CREATE A CUSTOM SYMBOL FUNCTION MIRRORING THE BUILT-IN FUNCTIONALITY
d3.svg.customSymbol = function() {
var type,
size = 64; // SET DEFAULT SIZE
function symbol(d,i) {
// GET THE SYMBOL FROM THE CUSTOM MAP
return customSymbolTypes.get(type.call(this,d,i))(size.call(this,d,i));
}
// DEFINE GETTER/SETTER FUNCTIONS FOR SIZE AND TYPE
symbol.type = function(_) {
if (!arguments.length) return type;
type = d3.functor(_);
return symbol;
};
symbol.size = function(_) {
if (!arguments.length) return size;
size = d3.functor(_);
return symbol;
};
return symbol;
};
Then, you could create a function to check if a symbol is in the list of built-in symbols, and if it's not, assume it is a custom symbol:
function getSymbol(type, size) {
// SIZE DEFAULTS TO 64 IF NOT GIVEN
size = size || 64;
// IF TYPE IS ONE OF THE BUILT-IN TYPES, CALL THE BUILT-IN FUNCTION
if (d3.svg.symbolTypes.indexOf(type) !== -1) {
return d3.svg.symbol().type(type).size(size)();
}
// OTHERWISE, CALL THE CUSTOM SYMBOL FUNCTION
else {
return d3.svg.customSymbol().type(type).size(size)();
}
}
HERE is a demo of this method in action.
I'll admit it seems kind of crazy to have to re-implement the whole symbol function like that. It might be worth a feature request on the github page asking to be able to provide a custom map of symbol definitions that could be read into the built-in method. Anyway, I hope that helps for now.
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