d3.js проблема масштабирования - PullRequest
0 голосов
/ 18 октября 2019

Я работаю над проектом 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-файл, я не восстановил эту функцию?

Большое спасибо заранее за вашу помощь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...