Javascript 通过缩放比例更新X轴

Javascript 通过缩放比例更新X轴,javascript,d3.js,Javascript,D3.js,我试图通过检查当前的缩放比例来创建动态x轴时间比例 它在第一次加载时工作,但如果我随后尝试放大或缩小图表,我的x轴不会响应,尽管我已将变量声明为函数,并期望它在每次调用缩放操作时返回适当的比例和轴 下面是我的代码。先谢谢你 d3.csv('data/sample.csv', function (data) { // sort out the data we'll be using data.forEach(function (d) { d.date = new D

我试图通过检查当前的缩放比例来创建动态x轴时间比例

它在第一次加载时工作,但如果我随后尝试放大或缩小图表,我的x轴不会响应,尽管我已将变量声明为函数,并期望它在每次调用缩放操作时返回适当的比例和轴

下面是我的代码。先谢谢你

d3.csv('data/sample.csv', function (data) {
    // sort out the data we'll be using
    data.forEach(function (d) {
        d.date = new Date(d.dateTime);
        d.Ranking = +d.weight;
    });

    // define the boundaries of the svg canvas
    var margin = {top : 30, right : 45, bottom : 30, left : 45},
    width = window.innerWidth - margin.left - margin.right,
    height = window.innerHeight - margin.top - margin.bottom;

    // define the scale for each axis
    var interval = 'hours';

    var xScale = d3.time.scale()
        .domain([d3.min(data, function (d) {
                    return d.date;
                }), d3.max(data, function (d) {
                    return d.date;
                })])
        .range([0, width])
        .nice();

    var xDaysScale = d3.time.scale()
        .domain([new Date(2014, 7, 1), new Date(2014, 7, 6)])
        .range([0, width])
        .nice();

    var xWeeksScale = d3.time.scale()
        .domain([new Date(2014, 7, 1), new Date(2014, 7, 31)])
        .range([0, width])
        .nice();

    var xMonthsScale = d3.time.scale()
        .domain([new Date(2014, 7, 1), new Date(2015, 0, 1)])
        .range([0, width])
        .nice();

    var yScale = d3.scale.linear().domain([0, 5]).range([height, 0]).nice();

    // define the axes
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .ticks(d3.time.hours, 1)
        .orient('bottom');

    var yAxis = d3.svg.axis().scale(yScale).orient('left');

    // define the zoom behavior
    var zm = d3.behavior.zoom()
        .x(xScale)
        .scaleExtent([.1, 1024])
        .on('zoom', zoom);

    // initialize the tooltip, and append it to the body
    var tooltip = d3.select('body')
        .append('div')
        .attr('class', 'tooltip')
        .attr('id', 'tooltip')
        .style('opacity', 0);

    // initialize the chart
    var svg = d3.select('.graph')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('svg:g')
        .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');

    // append the manipulation areas to the chart
    svg.append('rect')
    .attr('class', 'zoom xy')
    .attr('width', width)
    .attr('height', height)
    .call(zm)
    .on('dblclick.zoom', null) // disable the standard shitty doubleclick zoom function
    .on('dblclick', function (d) { // use my own awesome zoom function, that resets the chart
        // reset the main scale
        zm.scale(1);
        zm.translate([0, 0]);

        // let's not forget to update the axes
        svg.select('.x.axis').call(xAxis);
        svg.select('.y.axis').call(yAxis);

        // apply the changes
        update();
    });

    // append the axes to the chart
    svg.append('svg:g')
    .attr('class', 'x axis')
    .attr('transform', 'translate(-' + width + ', ' + height + ')')
    .attr('transform', 'translate(0, ' + height + ')')
    .call(xAxis);

    // create the elements based on the data provided
    var elem = svg.selectAll()
        .data(data)
        .enter()
        .append('g')
        .attr('class', 'element')
        .attr('transform', function (d) {
            return 'translate(' + xScale(d.date) + ', ' + yScale(d.Ranking) + ')';
        });

    // we append the full text description as a HTML element, because, a text element is more expensive, and doesn't support line breaks
    elem.append('foreignObject')
    .attr('width', 200)
    .attr('height', 1000)
    .append('xhtml:div')
    .attr('class', 'fulltext')
    .html(function (d) {
        return d.content;
    })
    .style('opacity', 0);

    // function::zoom - handles the scaling, translation of the chart elements
    function zoom() {
        //svg.select('.x.axis').call(xAxis);
        //svg.select('.y.axis').call(yAxis);

        //update();

        console.log(interval);

        if (zm.scale() < 1) {
            //console.log('zooming OUT');

            if (interval == 'hours') {
                xAxis = d3.svg.axis().scale(xDaysScale).ticks(d3.time.days, 1).orient("bottom");
                zm.x(xDaysScale);
                interval = 'days';
            }
            else if (interval == 'days') {
                xAxis = d3.svg.axis().scale(xWeeksScale).ticks(d3.time.weeks, 1).orient("bottom");
                zm.x(xWeeksScale);
                interval = 'weeks';
            }
            else if (interval == 'weeks') {
                xAxis = d3.svg.axis().scale(xMonthsScale).ticks(d3.time.months, 1).orient("bottom");
                zm.x(xMonthsScale);
                interval = 'months';
            }
        }

        else if (zm.scale() > 1) {
            //console.log('zooming IN');

            if (interval == 'months') {
                xAxis = d3.svg.axis().scale(xWeeksScale).ticks(d3.time.weeks, 1).orient("bottom");              
                zm.x(xWeeksScale);
                interval = 'weeks';
            }

            else if (interval == 'weeks') {
                xAxis = d3.svg.axis().scale(xDaysScale).ticks(d3.time.days, 1).orient("bottom");
                zm.x(xDaysScale);
                interval = 'days';
            }

            else if (interval == 'days') {
                xAxis = d3.svg.axis().scale(xScale).ticks(d3.time.hours, 1).orient("bottom");
                zm.x(xScale);
                interval = 'hours';
            }
        }

        svg.select('.x.axis').call(xAxis);
        svg.select('.y.axis').call(yAxis);
        update();
    }

    // function::resize - handles the responsive positioning and sizing of elements depending on the size of the viewport
    function resize() {

        // re-get the size of the window
        width = window.innerWidth - margin.left - margin.right,
        height = window.innerHeight - margin.top - margin.bottom;

        // re-set the size of the chart's range
        xScale.range([0, width]).nice();
        yScale.range([height, 0]).nice();

        // configure the chart to the new size
        d3.select('.graph')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom);

        // re-set the size of the manipulation area
        svg.select('rect')
        .attr('width', width)
        .attr('height', height);

        // re-size and re-position the axes
        svg.select('.x.axis')
        .attr('transform', 'translate(0, ' + height + ')')
        .call(xAxis);

        // update the elements according to the resized elements
        update();
    }

    // function::update - handles all redrawing of the chart and checking of dynamic elements
    function update() {
        // re-position individual elements
        svg.selectAll('.element')
        .attr('transform', function (d) {
            if (interval == 'hours') {
                return 'translate(' + xScale(d.date) + ', ' + yScale(d.Ranking) + ')';
            }

            if (interval == 'days') {
                return 'translate(' + xDaysScale(d.date) + ', ' + yScale(d.Ranking) + ')';
            }

            if (interval == 'weeks') {
                return 'translate(' + xWeeksScale(d.date) + ', ' + yScale(d.Ranking) + ')';
            }

            if (interval == 'months') {
                return 'translate(' + xMonthsScale(d.date) + ', ' + yScale(d.Ranking) + ')';
            }

            //return 'translate(' + xScale(d.date) + ', ' + yScale(d.Ranking) + ')';
        });

        d3.selectAll('.fulltext')
        .style('opacity', function (d) {
            // hide or show the full text descriptions based on zoom level
            if (zm.scale() >= 1) {
                return 1;
            } else {
                return 0;
            }
        });
    }

    // add the event handler for resizing
    d3.select(window).on('resize', resize);

    // refresh once to make sure all the processing gets through
    update();
});
宣布

xScale = returnScale() 
只需调用returnScale一次,听起来不像您想要的。在缩放或更新中,您需要再次调用returnScale,然后执行以下操作

zm.x(xScale) 

您好,谢谢您的快速回复。我试过你告诉我的。函数zoom{console.log'youcalledmeatzoom';returnScale;zm.xxScale;returnAxis;svg.select'.x.axis'.callxAxis;svg.select'.y.axis'.callyAxis;update;}但我的x轴在那之后的几天被阻塞了。你能给我进一步的建议吗?我也需要对xAxis做同样的操作吗?我认为这个if条件可能是错误的:else if zm.scale>=1应该是else if zm.scale,或者至少你需要一些其他条件来覆盖这个案例zm.scale谢谢你指出这一点!我现在正在进行更改和测试:
function zoom() {
    console.log('interval: ' + interval);
    console.log('zoom: ' + zm.scale());

    if (zm.scale() < 1) {
        if (interval == 'hours') {
            //xAxis = xDaysAxis;
            xDaysScale = d3.time.scale().domain([new Date(2014, 7, 1), new Date(2014, 7, 6)]).range([0, width]).nice();
            xAxis = d3.svg.axis().scale(xDaysScale).ticks(d3.time.days, 1).orient("bottom");
            zm.x(xDaysScale);
            interval = 'days';
        }
        else if (interval == 'days') {
            //xAxis = xWeeksAxis;
            xWeeksScale = d3.time.scale().domain([new Date(2014, 7, 1), new Date(2014, 7, 31)]).range([0, width]).nice();
            xAxis = d3.svg.axis().scale(xWeeksScale).ticks(d3.time.weeks, 1).orient("bottom");
            zm.x(xWeeksScale);
            interval = 'weeks';
        }
        else if (interval == 'weeks') {
            //xAxis = xMonthsAxis;
            xMonthsScale = d3.time.scale().domain([new Date(2014, 7, 1), new Date(2015, 0, 1)]).range([0, width]).nice();
            xAxis = d3.svg.axis().scale(xMonthsScale).ticks(d3.time.months, 1).orient("bottom");
            zm.x(xMonthsScale);
            interval = 'months';
        }
        else {
            //zm.x(xMonthsScale);
            //interval = 'months';
        }
    }
    else if (zm.scale() > 1) {
        if (interval == 'months') {
            //xAxis = xWeeksAxis;
            xWeeksScale = d3.time.scale().domain([new Date(2014, 7, 1), new Date(2014, 7, 31)]).range([0, width]).nice();
            xAxis = d3.svg.axis().scale(xWeeksScale).ticks(d3.time.weeks, 1).orient("bottom");
            zm.x(xWeeksScale);
            interval = 'weeks';
        }

        else if (interval == 'weeks') {
            //xAxis = xDaysAxis;
            xDaysScale = d3.time.scale().domain([new Date(2014, 7, 1), new Date(2014, 7, 6)]).range([0, width]).nice();
            xAxis = d3.svg.axis().scale(xDaysScale).ticks(d3.time.days, 1).orient("bottom");
            zm.x(xDaysScale);
            interval = 'days';
        }

        else if (interval == 'days') {
            //xAxis = xHoursAxis;
            xHoursScale = d3.time.scale()
                .domain([
                    //d3.min(data, function (d) { return d.date; }), 
                    //d3.max(data, function (d) { return d.date; })
                    mindate, maxdate
                    ])
                .range([0, width])
                .nice();
            xAxis = d3.svg.axis().scale(xHoursScale).ticks(d3.time.hours, 1).orient("bottom");
            zm.x(xHoursScale);
            interval = 'hours';
        }
        else {
            //zm.x(xHoursScale);
            //interval = 'hours';
        }
    }

    svg.select('.x.axis')
        //.attr('transform', 'translate(0, ' + height + ')')
        .call(xAxis);
    svg.select('.y.axis').call(yAxis);

    update();
}