简体   繁体   English

通过缩放比例更新X轴

[英]Update X-axis via zoom scale

I am trying to create a dynamic x-Axis time scale by checking my current zoom scale. 我正在尝试通过检查当前的缩放比例来创建动态的x轴时间比例。

It works on first load, but if I subsequently try to zoom in or out of the chart, my x-Axis doesn't response although I have declared the variable as a function and expect it to return the appropriate scale and axis every time a zoom action is called. 它在第一次加载时起作用,但是如果我随后尝试放大或缩小图表,尽管我已将变量声明为函数,并希望每次a都返回适当的比例尺和轴,但我的x轴没有响应。调用缩放动作。

My code below. 我的代码如下。 Thank you in advance. 先感谢您。

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

Declaring 宣告

xScale = returnScale() 

will just call returnScale once, which doesn't sound like what you want. 只会调用returnScale一次,这听起来不像您想要的。 In your zoom() or update() you need to call returnScale() again, and then do 在您的zoom()或update()中,您需要再次调用returnScale(),然后执行

zm.x(xScale) 
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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM