通过缩放比例更新X轴

时间:2014-09-13 06:07:58

标签: 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 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();
});

2 个答案:

答案 0 :(得分:0)

声明

xScale = returnScale() 

只会调用一次returnScale,这听起来并不像你想要的那样。在缩放()或更新()中,您需要再次调用returnScale(),然后执行

zm.x(xScale) 

答案 1 :(得分:0)

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();
}