Ho visto le direttive che utilizzano solo l'oggetto D3 globale, ho anche visto le direttive che iniettano l'oggetto D3 globale semplicemente restituendolo in un servizio, e ho visto direttive che aggiungi lo script D3 e restituisci una promessa risolta sul carico di script che fornisce l'oggetto D3.Convenzione corretta per l'iniezione di D3 in AngualrJS
L'utilizzo in un servizio iniettabile sembra avere più senso (vedere l'esempio 1 e 2), ma non sono sicuro di quale sia il modo migliore. L'Esempio 2 garantirebbe che D3 sia stato caricato prima di eseguire qualsiasi codice su di esso, ma non sembra che qualcuno lo faccia, in più vuol dire che è necessario avvolgere l'intera direttiva nel servizio altrimentie l'oggetto creato svg
è esaurito campo di applicazione o non definito (vedi esempio 2), ma almeno la promessa del compilazione credo sarebbe sempre risolvere prima, si veda l'esempio 3.
esempio 1: Servizio di passaggio D3 oggetto globale
.factory('D3Service', [,
function() {
// Declare locals or other D3.js
// specific configurations here.
return d3;
}]);
esempio 2: Servizio che aggiunge lo script D3 al DOM e promette di passare
.factory('D3Service', ['$window', '$document', '$q', '$rootScope',
function ($window, $document, $q, $rootScope) {
var defer = $q.defer();
var scriptTag = $document[0].createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.src = 'https://d3js.org/d3.v3.min.js';
scriptTag.async = true;
scriptTag.onreadystatechange = function() {
if (this.readyState == 'complete') {
onScriptLoad();
}
}
scriptTag.onload = onScriptLoad;
var script = $document[0].getElementsByTagName('body')[0];
script.appendChild(scriptTag);
//---
// PUBLIC API
//---
return {
d3: function() {
return defer.promise;
}
};
//---
// PRIVATE METHODS.
//---
// Load D3 in the browser
function onScriptLoad() {
$rootScope.$apply(function() {
defer.resolve($window.d3);
});
}
}]);
Esempio 3: Utilizzo Compile SVG aggiungendo non significa SVG è disponibile in collegamento, ma almeno la promessa del compilazione sarebbe sempre risolvere prima
// Perform DOM and template manipulations
function compile ($element, $attrs, $transclude) {
var svg;
// Callback provides raw D3 object
D3Service.d3().then(function (d3) {
// Create a responsive SVG root element
svg = d3.select($element[0])
.append('svg')
.style('width', '100%');
});
// Return the link function
return function($scope, $element, $attrs) {
// Is svg undefined?
// Maybe? so have to wrap everything again in service
D3Service.d3().then(function (d3) {
function render() {
// d3 and svg guaranteed to be available, but code gets really ugly looking and untestable
}
});
function render() {
// d3 and svg have to be passed in as they may not be available, but code is cleaner
}
};
}
Sì. A meno che d3.js faccia qualcosa di diverso dal porre 'd3' nell'oscilloscopio della finestra, niente è più elegante di una promessa' $ interval' per verificare se esiste eventualmente. [su IE8, comunque] – Brian
Salve @Brian, quindi nel 'link' di ciascuna direttiva del grafico è necessario attendere un intervallo di $ e quindi utilizzare il riferimento globale di D3? Sembra che la soluzione potrebbe/dovrebbe essere DRYer, ma forse no ... – mtpultz
Implementerei "Se d3 non è definito, quindi carica d3 e attendi, altrimenti risolvilo immediatamente". Se qualcuno ha una soluzione migliore per i browser tra cui IE8, per favore @ me! – Brian