mtp*_*ltz 7 javascript d3.js angularjs
我已经看到只使用全局D3对象的指令,我也看到了通过在服务中返回注入全局D3对象的指令,我看到了添加D3脚本并返回一个promise的指令解决了提供D3对象的脚本加载问题.
在注射服务中使用它似乎最有意义(参见示例1和2),但我不确定哪种方式更好.示例2将保证在运行任何代码之前已加载D3,但似乎没有人这样做,而且它意味着您必须将整个指令包装在服务中,否则d3创建的svg对象超出范围或可能是未定义的(参见示例2),但至少我认为将始终首先解析编译的承诺,请参见示例3.
示例1:服务传递D3全局对象
.factory('D3Service', [,
function () {
// Declare locals or other D3.js
// specific configurations here.
return d3;
}]);
Run Code Online (Sandbox Code Playgroud)
示例2:服务将D3脚本添加到DOM并传递promise
.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);
});
}
}]);
Run Code Online (Sandbox Code Playgroud)
示例3:使用编译添加SVG并不意味着SVG在Link中可用,但至少编译的承诺总是先解决
// 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
}
};
}
Run Code Online (Sandbox Code Playgroud)
d3当我遇到和的问题时,我也有类似的问题Angular。似乎有几种方法可以解决这个问题;每一个都是可行的,但没有一个感觉流畅或自然。从本质上讲,d3和Angular似乎是两种截然不同的技术,并且它们不能很好地协同工作。别误会我的意思,他们合作得非常好,但他们需要互相热身。因此,我们最多可以在框架d3内提供一个游乐场Angular。我相信这个游乐场应该是一个directive。
但是关于返回承诺的模块化d3Service方法(根据文件的加载d3.js):
angular.module('myApp.directives', ['d3'])
.directive('barChart', ['d3Service', function(d3Service) {
return {
link: function(scope, element, attrs) {
d3Service.d3().then(function(d3) {
// d3 is the raw d3 object
});
}}
}]);
Run Code Online (Sandbox Code Playgroud)
虽然ngNewsletter对此进行了非常详细的描述,但使用直接将标签写入 DOM 的服务似乎有些过分script,因为它可以包含在index.html所有其他 javascript 文件中。我的意思是,我们知道有一个directive使用此文件的文件,那么为什么不专门加载它呢?似乎不需要跳过障碍,只需:
<script src="/js/third-party/d3js/d3.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
然而,这种方法承诺确实提供了模块化——假设我们正在构建多个应用程序并且每个应用程序都需要d3,那么是的,能够非常轻松地d3在应用程序级别注入我们的模块是很棒的。但是,您总是必须等待该承诺,即使我们知道它会在初始加载后立即解决,您仍然需要解决它。在任何使用它的指令或控制器中。总是。真糟糕。
正如我所说,我选择只包含d3.js在我的 中index.html,因此我可以在我的指令中访问它,而无需解决承诺。这可能是一个相似之处:FWIW,我使用 JQuery 承诺而不是 Angular 承诺,那么当我需要 JQuery 时我该怎么办?好吧,我只是在需要时调用它 ( $.Deferred()),我的观点是,d3以类似的方式调用对我来说似乎并没有那么令人震惊。
虽然我确实使用了 a d3Service,但它更多的是用于辅助函数而不是其他任何东西。例如,当我想要获取要进行工作的 SVG 时,为什么不直接调用一个为我提供响应式 SVG 的函数:
指令(链接)
var svg = d3Service.getResponsiveCanvas(scope.id, margin, height, width);
Run Code Online (Sandbox Code Playgroud)
服务
app.service('d3Service', function() {
return {
getResponsiveCanvas: function(id, margin, height, width) {
return d3.select('#' + id)
.append('div')
.classed('svg-container', true)
.append('svg')
.attr('id', 'svg-' + id)
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('viewBox', '0 0 ' + (width + margin.left + margin.right) + ' ' + (height + margin.top + margin.bottom))
.classed('svg-content-responsive', true)
.append('g')
.attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
}
}
});
Run Code Online (Sandbox Code Playgroud)
我有类似的函数来向 SVG 添加轴。这确实有代码味道,但同样,就其本质而言,d3我们直接操作 DOM,所以我的经验是,无论我们把它放在哪里,它都会很丑陋,而且感觉不太像 Angular,所以你可能会这样做我们精心设计一些服务,让您的生活更轻松。
| 归档时间: |
|
| 查看次数: |
1192 次 |
| 最近记录: |