Javascript 加载数据一次,但使用全局变量“是否是一种良好的做法?”;var数据&引用;
我是js新手,读到关于变量的使用、各自的范围以及隐藏数据的方式,有“隐藏在阴影中的怪物” 我正在使用d3.js并从csv加载数据,但我只想进行一次GET调用,因为更复杂的可视化可能涉及10个csv文件,其中一些文件包含多达10000行数据-因此我在脚本“var data;”的顶部添加了一个变量它在初始渲染时被填充,然后在用户的后续交互中使用该变量 我的方法安全吗?如果有更好的模式,我应该使用什么 BarData.csv如下所示:Javascript 加载数据一次,但使用全局变量“是否是一种良好的做法?”;var数据&引用;,javascript,d3.js,Javascript,D3.js,我是js新手,读到关于变量的使用、各自的范围以及隐藏数据的方式,有“隐藏在阴影中的怪物” 我正在使用d3.js并从csv加载数据,但我只想进行一次GET调用,因为更复杂的可视化可能涉及10个csv文件,其中一些文件包含多达10000行数据-因此我在脚本“var data;”的顶部添加了一个变量它在初始渲染时被填充,然后在用户的后续交互中使用该变量 我的方法安全吗?如果有更好的模式,我应该使用什么 BarData.csv如下所示: Fruit,dt,amount Apple,12/28/2016,
Fruit,dt,amount
Apple,12/28/2016,-1256
Apple,12/29/2016,-500
Apple,12/30/2016,3694
Apple,12/31/2016,5586
Apple,1/1/2017,4558
Apple,1/2/2017,6696
Apple,1/3/2017,7757
Apple,1/4/2017,8528
Apple,1/5/2017,5543
Apple,1/6/2017,3363
Apple,1/7/2017,5464
Pear,12/25/2017,250
Pear,12/26/2017,669
Pear,12/27/2017,441
Pear,12/28/2017,159
Pear,12/29/2017,357
Pear,12/30/2017,775
Pear,12/31/2017,669
代码都在一个html
文件中,如下所示:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>BAR SINGLE FUNCTION</title>
<script src="http://d3js.org/d3.v3.js"></script>
<style type="text/css">
#radioDiv {
top: 45px;
font-family: verdana;
font-size: 8px;
width: 455px;
}
#TOPbarChart {
position: absolute;
top: 50px;
left: 30px;
width: 750px;
height: 195px;
}
.axis--y path,
.axis--x path {
display: none;
}
.axis--x line,
.axis--y line {
stroke: black;
fill: none;
stroke-width: 2px
}
.yAxis text,
.xAxis text {
font: 7pt Verdana;
stroke: none;
fill: black;
}
.title,
.titleX {
font-family: Verdana;
font-size: 10px;
}
</style>
</head>
<body>
<div id="radioDiv">
<label>
<input id="radioFrt" type="radio" name="frt" value="Apple" class="radioB" checked> APPLE
</label>
<label>
<input type="radio" name="frt" value="Pear" class="radioB"> PEAR
</label>
</div>
<div id="TOPbarChart"></div>
<script type="text/javascript">
var currentFruit = "Apple";
var currentColr = "#00a5b6";
var barDataCSV_Dly = "BarData.csv";
var data;
//
//
// radio button
document.getElementById("radioFrt").checked = true;
d3.selectAll('input[name="frt"]').on("change", function change() {
currentFruit = this.value;
//load();
TOPbarChart(currentFruit, currentColr);
});
//FORMATS
var parseDate = d3.time.format("%m/%d/%Y").parse;
//
// BASIC SIZING
//
function barChartBasics() {
var margin = {
top: 25,
right: 35,
bottom: 25,
left: 70
},
width = 550 - margin.left - margin.right,
height = 155 - margin.top - margin.bottom,
colorBar = d3.scale.category20(),
barPaddingFine = 1,
barPaddingThick = 2;
return {
margin: margin,
width: width,
height: height,
colorBar: colorBar,
barPaddingFine: barPaddingFine,
barPaddingThick: barPaddingThick
};
}
// create svg element
var basics = barChartBasics();
var svg = d3.select("#TOPbarChart")
.append("svg")
.attr({
"width": basics.width + basics.margin.left + basics.margin.right,
"height": basics.height + basics.margin.top + basics.margin.bottom,
id: "svgTOPbarChart"
});
// create svg group
var plot = svg
.append("g")
.attr({
"transform": "translate(" + basics.margin.left + "," + basics.margin.top + ")",
id: "svgPlotTOPbarChart"
});
var axisPadding = 2;
var leftAxisGroup = svg
.append('g')
.attr({
transform: 'translate(' + (basics.margin.left - axisPadding) + ',' + (basics.margin.top) + ')',
'class': "yAxis axis--y",
id: "yAxisGTOPbarChart"
});
var bottomAxisGroup = svg
.append('g')
.attr({
'class': "xAxis axis--x",
id: "xAxisGTOPbarChart"
});
var titleTxt = svg.append("text")
.attr({
x: basics.margin.left + 12,
y: 20,
'class': "title",
'text-anchor': "start"
})
// create scales with ranges
var xScale = d3.time.scale().range([0, basics.width]);
var yScale = d3.scale.linear().range([basics.height, 0]);
function load(){
d3.csv(barDataCSV_Dly, function(rows) {
data = rows;
TOPbarChart(currentFruit, currentColr)
})
}
function TOPbarChart(
frt, colorChosen) {
// get the data
//d3.csv(barDataCSV_Dly, function(rows) {
TOPbarData = data.map(function(d) {
return {
"Fruit": d.Fruit,
"dt": parseDate(d.dt),
"amount": +d.amount
};
}).filter(function(row) {
if (row['Fruit'] == frt) {
return true;
}
});
// create domains for the scales
xScale.domain(d3.extent(TOPbarData, function(d) {
return d.dt;
}));
var amounts = TOPbarData.map(function(d) {
return d.amount;
});
var yMax = d3.max(amounts);
var yMin = d3.min(amounts);
var yMinFinal = 0;
if (yMin < 0) {
yMinFinal = yMin;
}
yScale.domain([yMinFinal, yMax]);
// introduce the bars
// var plot = d3.select("#svgPlotTOPbarChart")
var sel = plot.selectAll("rect")
.data(TOPbarData);
sel.enter()
.append("rect")
.attr({
x: function(d, i) {
return xScale(d.dt);
},
y: function(d) {
return yScale(Math.max(0, d.amount));
},
width: (basics.width / TOPbarData.length - basics.barPaddingFine),
height: function(d) {
return Math.abs(yScale(d.amount) - yScale(0));
},
//fill: colorChosen,
fill: function(d, i) {
return d.amount < 0 ? "#FF0000" : colorChosen;
},
// fill: function(d, i) {
// var col = colorChosen
// if (d.amount < 0) {
// col = "#FF0000";
// }
// return col;
// },
'class': "bar"
});
// this little function will create a small ripple affect during transition
var dlyRipple = function(d, i) {
return i * 100;
};
sel
.transition()
.duration(dlyRipple) //1000
.attr({
x: function(d, i) {
return xScale(d.dt);
},
y: function(d) {
return yScale(Math.max(0, d.amount));
},
width: (basics.width / TOPbarData.length - basics.barPaddingFine),
height: function(d) {
return Math.abs(yScale(d.amount) - yScale(0));
},
//fill: colorChosen
fill: function(d, i) {
var col = colorChosen
if (d.amount < 0) {
col = "#FF0000";
}
return col;
},
});
sel.exit().remove();
// add/transition y axis - with ticks and tick markers
var axisY = d3.svg.axis()
.orient('left')
.scale(yScale)
.tickFormat(d3.format("s")) // use abbreviations, e.g. 5M for 5 Million
.outerTickSize(0);
leftAxisGroup.transition().duration(1000).call(axisY);
// add/transition x axis - with ticks and tick markers
var axisX = d3.svg.axis()
.orient('bottom')
.scale(xScale);
bottomAxisGroup
.attr({
transform: 'translate(' + (basics.margin.left + ((basics.width / TOPbarData.length) / 2)) + ',' + (basics.margin.top + basics.height) + ')',
})
.transition().duration(1000).call(axisX.ticks(5));
titleTxt.text("Daily: last " + TOPbarData.length + " days");
// console.log(TOPbarData.length)
//});
}
//
//
//
//
load()
//TOPbarChart(currentFruit, currentColr);
//
//
//
//
</script>
</body>
</html>
在随后的函数中,我有以下内容:
var x = Module_BarDataDaily.dataX;
TOPbarData = x.map(function(d) { /<<< Type error x is undefined
return {
...
var x=Module\u BarDataDaily.dataX;
TOPbarData=x.map(函数(d){/在变量中缓存记录并不坏,除非它是私有的,并且在脚本中的任何其他地方都不可见
您当前的方法在全局名称空间中设置数据
变量,基本上,如果您包含的任何其他插件也包含名为数据
的变量,则可能会覆盖其值。-这是不安全的
要向世界其他地方隐藏变量,您可能希望在自调用函数中包含所有代码:
(function() {
var data = ...; // It's accessible only in that function
// Your JavaScript code
})();
相关说明:
如果要在文件之间共享变量,请在对象(称为模块)内执行,例如:
JavaScript提供了类似于Python的内置模块系统,但是浏览器还不支持它
相关说明:
PS:将CSS和JavaScript与外部文件分开以避免混乱。在更新您的问题后,还有一个问题称为异步数据
库函数d3.csv(…)
与其他计算异步工作,这意味着您永远无法确定数据是否已填充。它可能是立即填充的,也可能是几秒钟后填充的
这就是为什么x是未定义的
,因为在解析该代码时,d3.csv
尚未完成计算
处理此代码的最简单尝试是使用回调
函数。
基本上,您的模块返回函数loadData
,该函数接受函数,只有当模块知道data
已填充时才会调用该函数
var Module_BarDataDaily = (function() {
var data;
return {
loadData: lazyLoadData
};
function lazyLoadData(callback) {
if (data) {
callback(data); // data already exists, run function
} else {
d3.csv("myData.csv", function(rows) {
data = rows;
callback(data); // data is filled, run function
});
}
}
})();
下面是如何将其用于该尝试
Module_BarDataDaily.loadData(function(data) {
// this function loads only after data is filled
TopChartData = data.map(...);
});
什么是回调?
简单地说,回调函数就像一个“调用
完成任务后,返回给经理
- 资料来源:
注意:还有许多其他可能更好的解决此类问题的尝试,如ES2015中的Promise
,wait
,将与ES2017一起发布。我不清楚您在问题主体中问了什么。标题的答案是“不,拥有一个全球性的数据
——或者实际上,任何其他全球性的数据都不是最佳做法。”@T.J.Crowder为不够清晰表示歉意。就这一点而言,“我的方法安全吗?如果有更好的模式,我应该使用什么?“你们是说我的方法不安全……那个么什么样的方法才是最好的做法呢?我尝试了你们的建议,但得到了一个未定义的错误?我已经尝试修正了这个问题。@为什么问:这是不同的问题,所以我添加了另一个答案。希望我没有在代码中输入错误;)这是非常感谢你Piotr花时间为我添加这些额外的信息-谢谢你。
var Module_BarDataDaily = (function() {
var data;
return {
loadData: lazyLoadData
};
function lazyLoadData(callback) {
if (data) {
callback(data); // data already exists, run function
} else {
d3.csv("myData.csv", function(rows) {
data = rows;
callback(data); // data is filled, run function
});
}
}
})();
Module_BarDataDaily.loadData(function(data) {
// this function loads only after data is filled
TopChartData = data.map(...);
});