Я работаю над проектом django, в котором интенсивно использую d3.js. У меня есть функция JavaScript, которая работает хорошо:
function three_lines_pan_zoom_chart(id, data, options) {
var plotChart = d3.select(id).classed('chart', true).append('svg')
.attr('width', options.w + options.margin.left + options.margin.right)
.attr('height', options.h + options.margin.top + options.margin.bottom)
.append('g')
.attr('transform', 'translate(' + options.margin.left + ',' + options.margin.top + ')');
var plotArea = plotChart.append('g')
.attr('clip-path', 'url(#plot_Area_Clip)');
plotArea.append('clipPath')
.attr('id', 'plot_Area_Clip')
.append('rect')
.attr({ width: options.w, height: options.h });
var navChart = d3.select(id).classed('complex_chart', true).append('svg')
.classed('navigator', true)
.attr('width', options.nav_w + options.margin.left + options.margin.right)
.attr('height', options.nav_h + options.margin.top + options.margin.bottom)
.append('g')
.attr('transform', 'translate(' + options.margin.left + ',' + options.margin.top + ')');
var minN = d3.min(data, function (d) { return d.date; }).getTime(),
maxN = d3.max(data, function (d) { return d.date; }).getTime();
var minDate = new Date(minN - 8.64e7),
maxDate = new Date(maxN + 8.64e7);
var yMin = d3.min(data, function (d) { return Math.min(d.value, d.valueBchk, d.valueIdx); }),
yMax = d3.max(data, function (d) { return Math.max(d.value, d.valueBchk, d.valueIdx); });
var xScale = d3.time.scale()
.domain([minDate, maxDate])
.range([0, options.w]),
yScale = d3.scale.linear()
.domain([yMin, yMax]).nice()
.range([options.h, 0]);
var navXScale = d3.time.scale()
.domain([minDate, maxDate])
.range([0, options.nav_w]),
navYScale = d3.scale.linear()
.domain([yMin, yMax])
.range([options.nav_h, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
plotChart.append('g')
.attr('class', 'x axis')
.style("fill", "#6C5373")
.attr('transform', 'translate(0,' + options.h + ')')
.call(xAxis);
plotChart.append("text") // text label for the x axis
.attr("transform", "translate(" + (options.w / 2) + " ," + (options.h + options.margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Dates");
plotChart.append('g')
.attr('class', 'y axis')
.style("fill", "#6C5373")
.call(yAxis);
plotChart.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.style("fill", "#6C5373")
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Cumulative Returns");
var navXAxis = d3.svg.axis()
.scale(navXScale)
.orient('bottom');
navChart.append('g')
.attr('class', 'x axis')
.style("fill", "#6C5373")
.attr('transform', 'translate(0,' + options.nav_h + ')')
.call(navXAxis);
var line = d3.svg.line()
.x(function (d) { return xScale(d.date); })
.y(function (d) { return yScale(d.value); });
var line2 = d3.svg.line()
.x(function (d) { return xScale(d.date); })
.y(function (d) { return yScale(d.valueBchk); });
var line3 = d3.svg.line()
.x(function (d) { return xScale(d.date); })
.y(function (d) { return yScale(d.valueIdx); });
plotArea.append('g')
.attr('class', 'line')
.datum(data)
.call(line);
plotArea.append('g')
.attr('class', 'line')
.datum(data)
.call(line2);
plotArea.append('g')
.attr('class', 'line')
.datum(data)
.call(line3);
var navData = d3.svg.area()
.x(function (d) { return navXScale(d.date); })
.y0(options.nav_h)
.y1(function (d) { return navYScale(d.value); });
var navLine = d3.svg.line()
.x(function (d) { return navXScale(d.date); })
.y(function (d) { return navYScale(d.value); });
plotArea.append("path")
.datum(data)
.attr("class", "FdLine")
.style("stroke", "#996A4E")
.attr("d", line);
plotChart.append("text")
.attr("transform", "translate(" + (options.w + 3) + "," + yScale(data[data.length - 1].value) + ")")
.attr("dy", ".35em")
.style("fill", "#996A4E")
.attr("text-anchor", "start")
.attr("class", "legFD")
.text(data[0].name);
plotArea.append("path")
.datum(data)
.attr("class", "Bchkline")
.style("stroke", "#45538C")
.attr("d", line2);
plotChart.append("text")
.attr("transform", "translate(" + (options.w + 3) + "," + yScale(data[data.length - 1].valueBchk) + ")")
.attr("dy", ".35em")
.style("fill", "#45538C")
.attr("text-anchor", "start")
.attr("class", "legBchk")
.text(data[0].bchk_name);
plotArea.append("path")
.datum(data)
.attr("class", "Idxline")
.style("stroke", "D994B0")
.attr("d", line3);
plotChart.append("text")
.attr("transform", "translate(" + (options.w + 3) + "," + yScale(data[data.length - 1].valueIdx) + ")")
.attr("dy", ".35em")
.style("fill", "D994B0")
.attr("text-anchor", "start")
.attr("class", "legIdx")
.text(data[0].idx_name);
navChart.append('path')
.attr('class', 'data')
.attr('d', navData(data));
navChart.append('path')
.attr('class', 'line')
.attr('d', navLine(data));
var viewport = d3.svg.brush()
.x(navXScale)
.on("brush", function () {
xScale.domain(viewport.empty() ? navXScale.domain() : viewport.extent());
redrawChart(data);
});
var zoom = d3.behavior.zoom()
.x(xScale)
.on('zoom', function () {
if (xScale.domain()[0] < minDate) {
var x = zoom.translate()[0] - xScale(minDate) + xScale.range()[0];
zoom.translate([x, 0]);
} else if (xScale.domain()[1] > maxDate) {
var x = zoom.translate()[0] - xScale(maxDate) + xScale.range()[1];
zoom.translate([x, 0]);
}
redrawChart(data);
updateViewportFromChart();
});
navChart.append("g")
.attr("class", "viewport")
.call(viewport)
.selectAll("rect")
.attr("height", options.nav_h);
var overlay = d3.svg.area()
.x(function (d) { return xScale(d.date); })
.y0(0)
.y1(options.h);
plotArea.append('path')
.attr('class', 'overlay')
.attr('d', overlay(data))
.call(zoom);
viewport.on("brushend", function () {
updateZoomFromChart();
});
xScale.domain([
data[0].date,
data[data.length - 1].date
]);
function redrawChart(data) {
var posXScale = xScale.domain()[1];
var myMth = posXScale.getMonth();
var myYear = posXScale.getFullYear();
//data.setMonths(data.getMonth() + 1, 0, 23, 59, 59, 0)
//var dateEom = getLastDateOfMonth(1999, 8);
var myDates = data.map(function(b) {return b.date;});
//var position = data.indexOf(dateEom);
var isDateEom = false;
var position = myDates.length-1;
for (var i = 0; i < myDates.length; i++) {
if (myDates[i].getMonth() == myMth && myDates[i].getFullYear() == myYear) {
isDateEom = true;
position = i;
break;
}
}
plotChart.select(".FdLine").attr("d", line);
plotChart.select(".Bchkline").attr("d", line2);
plotChart.select(".Idxline").attr("d", line3);
plotChart.select(".legFD").attr("transform", "translate(" + (options.w + 3) + "," + yScale(data[position].value) + ")");
plotChart.select(".legBchk").attr("transform", "translate(" + (options.w + 3) + "," + yScale(data[position].valueBchk) + ")");
plotChart.select(".legIdx").attr("transform", "translate(" + (options.w + 3) + "," + yScale(data[position].valueIdx) + ")");
plotChart.select('.x.axis').call(xAxis);
}
function updateViewportFromChart() {
if ((xScale.domain()[0] <= minDate) && (xScale.domain()[1] >= maxDate)) {
viewport.clear();
}
else {
viewport.extent(xScale.domain());
}
navChart.select('.viewport').call(viewport);
}
function updateZoomFromChart() {
zoom.x(xScale);
var fullDomain = maxDate - minDate,
currentDomain = xScale.domain()[1] - xScale.domain()[0];
var minScale = currentDomain / fullDomain,
maxScale = minScale * 20;
zoom.scaleExtent([minScale, maxScale]);
}
function getLastDateOfMonth(Year, Month) {
return (new Date((new Date(Year, Month + 1, 1)) - 1));
}
redrawChart(data);
updateZoomFromChart();
updateViewportFromChart();
Я вызываю эту функцию из сценария HTML:
{% load staticfiles %}
{% load static %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript" src="{% static "fund/charts.js" %}"></script>
<script>
var width_init_pzc = $("{{ id_chart }}").width(),
margin_pzc = { top: (width_init_pzc*30)/1000, right: (width_init_pzc*140)/1000,
bottom: (width_init_pzc*50)/1000, left: (width_init_pzc*120)/1000 },
width_pzc = width_init_pzc - margin_pzc.left - margin_pzc.right,
height_pzc = 500 - margin_pzc.top - margin_pzc.bottom,
height_pzc2 = $("{{ id_chart }}").height();
var navWidth_init_pzc = width_init_pzc,
navHeight_init_pzc = 100 - margin_pzc.top - margin_pzc.bottom;
var formatDate = d3.time.format("%Y-%m-%d").parse;
var palette_color_pzc= ["#6C5373", "#8BADD9", "#B6D6F2", "#45788C", "#6E87F2", "996A4E", "BF7761",
"735360", "D994B0", "6C5373", "7F805E", "A6A27A", "48BDCC", "FFC956", "#F2F2F2"];
var chartOptions_pzc = {
w: width_pzc,
h: height_pzc,
margin: margin_pzc,
paletteColor: palette_color_pzc,
nav_w: navWidth_init_pzc,
nav_h: navHeight_init_pzc
};
d3.json("{% url "fund:data_cumulative_returns_chart" fund %}", function (error, data) {
if (error) throw error;
console.log(data)
data.forEach(function (d) {
d.date = formatDate(d.date);
d.value = +d.value;
d.valueBchk = +d.valueBchk;
d.valueIdx = +d.valueIdx;
})
//Call function to draw the multiple lines chart
three_lines_pan_zoom_chart("{{ id_chart }}", data, chartOptions_pzc);
});
Я создал другую функцию HTML, которая называетсята же функция JavaScript:
{% load staticfiles %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript" src="{% static "fund/charts.js" %}"></script>
<script>
var width_init_ts_pf = $("#vami_portfolio").width(),
margin_ts_pf = { top: (width_init_ts_pf*30)/1000, right: (width_init_ts_pf*50)/1000, bottom: (width_init_ts_pf*50)/1000, left: (width_init_ts_pf*50)/1000 },
width_ts_pf = width_init_ts_pf - margin_ts_pf.left - margin_ts_pf.right,
height_ts_pf = 500 - margin_ts_pf.top - margin_ts_pf.bottom,
height2 = $("#vami_portfolio").height();
var navWidth_ts_pf = width_ts_pf,
navHeight_ts_pf = 100 - margin_ts_pf.top - margin_ts_pf.bottom;
var formatDate = d3.time.format("%Y-%m-%d").parse;
var palette_color_ts_pf = ["#6C5373", "#8BADD9", "#B6D6F2", "#45788C", "#6E87F2", "996A4E", "BF7761",
"735360", "D994B0", "6C5373", "7F805E", "A6A27A", "48BDCC", "FFC956", "#F2F2F2"];
var chartOptions_ts_pf = {
w: width_ts_pf,
h: height_ts_pf,
margin: margin_ts_pf,
paletteColor: palette_color_ts_pf,
nav_w: navWidth_ts_pf,
nav_h: navHeight_ts_pf
};
d3.json("{% url "portfolio:data_cumulative_returns" portfolio type %}", function (error, data) {
if (error) throw error;
console.log(data)
data.forEach(function (d) {
d.date = formatDate(d.date);
d.value = +d.value;
d.valueBchk = +d.valueBchk;
d.valueIdx = +d.valueIdx;
});
//Call function to draw the multiple lines chart
three_lines_pan_zoom_chart("{{ id_chart }}", data, chartOptions_ts_pf);
});
</script>
С момента создания второго HTML-скрипта функция масштабирования больше не работает для первого графика. Кроме того, когда я попытался удалить второй HTML-скрипт, я не восстановил функциональность панорамирования. Можно ли использовать функцию масштабирования панорамирования для нескольких SVG? У кого-то есть идея, почему pan-zoom работает только для второго скрипта и почему, когда я удалил второй HTML-файл, я не восстановил эту функцию?
Большое спасибо заранее за вашу помощь