2016-09-13 2 views
0

Я использую d3.js для создания графической сетки с 2-мя осями. Данные отображаются с использованием ячеек, цвет которых изменится в зависимости от значения данных. Простой пример виден here. Диаграмма создается как изображение svg. У меня проблема с отсечением области данных: при масштабировании и панорамировании данные перекрывают оси. Вы можете увидеть это в приведенном примере, щелкнув содержимое диаграммы и перетащив вверх или влево.Графическое содержание перекрывает оси с d3.js

Кто-нибудь знает, как я могу заставить данные исчезнуть под осями?

Вот код машинопись я использовал для создания диаграммы:

let cellSize = 49; 
let borderSize = 5; 
let margin = { top: 40, right: 40, bottom: 40, left: 40 }; 

function createChart() { 
    // Create test data 
    let count = 500; 
    let perLine = 50; 
    let markers = []; 
    for (let i = 0; i < count; i++) { 
     let id = i + 1; 
     let line = Math.floor(i/perLine) + 1; 
     let point = i % perLine + 1; 
     markers.push({id: id, line: line, point: point}); 
    } 
    //--- 

    let lineMin = d3.min(markers, (item) => item.line); 
    let lineMax = d3.max(markers, (item) => item.line); 
    let pointMin = d3.min(markers, (item) => item.point); 
    let pointMax = d3.max(markers, (item) => item.point); 

    let chart = document.querySelector('.chart'); 

    let viewWidth = chart.clientWidth - 2; 
    let viewHeight = 400; 
    let chartWidth = cellSize * (pointMax - pointMin + 1); 
    let chartHeight = cellSize * (lineMax - lineMin + 1); 

    let point = d3.scale.linear() 
      .domain([pointMin, pointMax]) 
      .range([cellSize/2, chartWidth - cellSize/2]); 

    let line = d3.scale.linear() 
     .domain([lineMin, lineMax]) 
     .range([cellSize/2, chartHeight - cellSize/2]); 

    let pointAxis = d3.svg.axis() 
     .scale(point) 
     .tickSize(0) 
     .tickValues(d3.range(pointMin, pointMax + 1)) 
     .orient('top'); 

    let lineAxis = d3.svg.axis() 
     .scale(line) 
     .tickSize(0) 
     .tickValues(d3.range(lineMin, lineMax + 1)) 
     .orient('left'); 

    let zoom = d3.behavior.zoom() 
     .x(point) 
     .y(line) 
     .scaleExtent([0.1, 1]) 
     .on('zoom',() => { 
     let width = Math.min(viewWidth - margin.left - margin.right, chartWidth); 
     let height = Math.min(viewHeight - margin.top - margin.bottom, chartHeight); 
     let t = zoom.translate(); 
     let tx = Math.min(t[0], 0); 
     tx = Math.max(tx, width - chartWidth); 
     let ty = Math.min(t[1], 0); 
     ty = Math.max(ty, height - chartHeight); 
     zoom.translate([tx, ty]); 
     let scale = zoom.scale(); 

     svg.select('.x.axis').call(pointAxis).selectAll('text') 
      .attr('x', -3) 
      .attr('y', 5) 
      .attr('transform', 'rotate(90)') 
      .style('text-anchor', 'end'); 
     svg.select('.y.axis').call(lineAxis); 

     grid.attr('transform', `translate(${[tx, ty]})scale(${scale})`); 
     }); 

    let svg = d3.select('.chart').append('svg') 
     .attr('id', 'svg') 
     .attr('width', viewWidth) 
     .attr('height', viewHeight) 
     .append('g') 
     .attr('transform', `translate(${margin.left}, ${margin.top})`) 
     .call(zoom); 

    let grid = svg.append('g') 
     .attr('id', 'grid'); 

    // Add the grid background 
    grid.append('rect') 
     .attr('class', 'grid') 
     .attr('x', 0) 
     .attr('y', 0) 
     .attr('width', chartWidth) 
     .attr('height', chartHeight); 

    // Create the cells 
    let cell = grid.selectAll('.cell') 
     .data(markers).enter() 
     .append('g') 
     .attr('id', (marker) => `cell${marker.line}-${marker.point}`) 
     .attr('class', 'cell') 
     .attr('transform', (marker) => `translate(${point(marker.point) - cellSize/2}, ${line(marker.line) - cellSize/2})`); 

    cell.append('rect') 
     .attr('class', 'border') 
     .attr('x', 0) 
     .attr('y', 0) 
     .attr('width', cellSize) 
     .attr('height', cellSize); 

    cell.append('rect') 
     .attr('class', (marker) => `fill valid`) 
     .attr('x', borderSize) 
     .attr('y', borderSize) 
     .attr('width', cellSize - 2 * borderSize) 
     .attr('height', cellSize - 2 * borderSize); 

    cell.append('rect') 
     .attr('class', 'selection') 
     .attr('x', 0) 
     .attr('y', 0) 
     .attr('width', cellSize) 
     .attr('height', cellSize); 

    // Add the axes 
    svg.append('g') 
     .attr('class', 'x axis') 
     .call(pointAxis) 
     .selectAll('text') 
     .attr('x', -3) 
     .attr('y', 5) 
     .attr('transform', 'rotate(90)') 
     .style('text-anchor', 'end'); 

    svg.append('g') 
     .attr('class', 'y axis') 
     .call(lineAxis); 
} 
+0

Ваша проблема заключается в том, что вы _not_ отсечение ничего. Посмотрите здесь: https://developer.mozilla.org/en/docs/Web/SVG/Element/clipPath – ksav

ответ

1

Если вам не нужно на самом деле использовать clipPath, вы можете просто добавить простой Б.Г. для оси х, как это, прежде чем добавить оси.

// Add bg for x axis 
    svg.append('rect') 
    .attr('height', 30) 
    .attr('y', -25) 
    .attr('fill', 'white') 
    .attr('width', chartWidth); 

Plunkr: https://plnkr.co/edit/tVZb7YEaDTMZaFX4Nod3?p=preview

+0

Я не добавлял фона для осей, потому что все примеры, которые я нашел с помощью d3.js, не используют нужно сделать это, чтобы «закрепить» правильно. Например: http://bl.ocks.org/mbostock/3892928 или http://bl.ocks.org/stepheneb/1182434 – osechet

+0

Не совсем сопоставимо. Эти примеры рисуют сетку с осями d3. Вы рисуете сетку, просто добавляя прямоугольники. – ksav

Смежные вопросы