D3 позиционирование пользовательского SVG на scattersplot - PullRequest
0 голосов
/ 30 апреля 2018

У меня есть диаграмма рассеяния, работающая так, как я ожидаю, когда добавляю простые круги SVG на график. Круги появляются в правильных положениях.

При попытке продублировать это позиционирование с помощью пользовательского изображения SVG с использованием аналогичного кода, иллюстрации появляются, но координаты немного смещены. Мне интересно, связано ли это с тем фактом, что я пытаюсь встроить тег SVG в другой SVG и значения окна просмотра. Атрибуты x и y устанавливаются правильно при проверке, они равны значениям cx и cy соответствующих кружков.

Код здесь https://codepen.io/kylehagler/pen/VxPqyM

var margin = { top: 20, right: 20, bottom: 30, left: 40 },
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

/* 
 * value accessor - returns the value to encode for a given data object.
 * scale - maps value to a visual display encoding, such as a pixel position.
 * map function - maps from data value to display value
 * axis - sets up axis
 */

// setup x
var xValue = function(d) {
        return d.episode;
    },
    xScale = d3.scale.linear().range([0, width]),
    xMap = function(d) {
        return xScale(xValue(d));
    },
    xAxis = d3.svg
        .axis()
        .scale(xScale)
        .orient('bottom');

// setup y
var yValue = function(d) {
        return d['year'];
    }, // data -> value
    yScale = d3.scale.linear().range([height, 0]), // value -> display
    yMap = function(d) {
        return yScale(yValue(d));
    }, // data -> display
    yAxis = d3.svg
        .axis()
        .scale(yScale)
        .orient('left')
        .ticks(5)
        .tickFormat(d3.format('d'));

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

// add the tooltip area to the webpage
var tooltip = d3
    .select('body')
    .append('div')
    .attr('class', 'tooltip')
    .style('opacity', 0);

var myData = [
    {
        episode: 1,
        type: 'book',
        title: 'The Crisis of the Old Order',
        author: 'Arthur Schlesinger Jr.',
        year: 1957,
        image: ''
    },
    {
        episode: 1,
        type: 'book',
        title: 'The View from Chivo',
        author: 'H. Allen Smith',
        year: 1971,
        image: ''
    },
    {
        episode: 1,
        type: 'book',
        title: 'The Peking Man is Missing',
        author: 'Claire Taschdjian',
        year: 1977,
        image: ''
    },
    {
        episode: 1,
        type: 'book',
        title: 'La Presidentia',
        author: 'Lois Gould',
        year: 1982,
        image: ''
    },
    {
        episode: 1,
        type: 'book',
        title: 'Masterpieces of World Literature in Digest Form',
        author: 'Frank Magill',
        year: 1952,
        image: ''
    },
    {
        episode: 3,
        type: 'book',
        title: "Lady Chatterly's Lover",
        author: 'D.H. Lawrence',
        year: 1928,
        image: ''
    },
    {
        episode: 4,
        type: 'book',
        title: 'Italy',
        author: 'Herbert Kubly',
        year: 1961,
        image: ''
    },
    {
        episode: 4,
        type: 'book',
        title: 'Nursery Friends from France',
        author: 'Olive Beaupre Miller',
        year: 1925,
        image: ''
    },
    {
        episode: 6,
        type: 'book',
        title: 'The Best of Everything',
        author: 'Rona Jaffe',
        year: 1958,
        image: ''
    },
    {
        episode: 6,
        type: 'book',
        title: 'Exodus',
        author: 'Leon Uris',
        year: 1958,
        image: ''
    },
    {
        episode: 8,
        type: 'book',
        title: 'Atlas Shrugged',
        author: 'Ayn Rand',
        year: 1957,
        image: ''
    }
];


// change string (from CSV) into number format
myData.forEach(function(d) {
  d.episode = +d.episode;
  d['year'] = +d['year'];
  //    console.log(d);
});

// don't want dots overlapping axis, so add in buffer to data domain
xScale.domain([d3.min(myData, xValue) - 1, 13]);
yScale.domain([d3.min(myData, yValue) - 1, d3.max(myData, yValue) + 1]);

// x-axis
svg
  .append('g')
  .attr('class', 'x axis')
  .attr('transform', 'translate(0,' + height + ')')
  .call(xAxis)
  .append('text')
  .attr('class', 'label')
  .attr('x', width)
  .attr('y', -6)
  .style('text-anchor', 'end')
  .text('episode');

// y-axis
svg
  .append('g')
  .attr('class', 'y axis')
  .call(yAxis)
  .append('text')
  .attr('class', 'label')
  .attr('transform', 'rotate(-90)')
  .attr('y', 6)
  .attr('dy', '.71em')
  .style('text-anchor', 'end')
  .text('year');

// draw dots
svg
  .selectAll('.dot')
  .data(myData)
  .enter()
  .append('circle')
  .attr('class', 'dot')
  .attr('r', 3.5)
  .attr('cx', xMap)
  .attr('cy', yMap)
  .on('mouseover', function(d) {
  tooltip
    .transition()
    .duration(200)
    .style('opacity', 0.9);
  tooltip
    .html(d['Cereal Name'] + '<br/> (' + xValue(d) + ', ' + yValue(d) + ')')
    .style('left', d3.event.pageX + 5 + 'px')
    .style('top', d3.event.pageY - 28 + 'px');
})
  .on('mouseout', function(d) {
  tooltip
    .transition()
    .duration(500)
    .style('opacity', 0);
});

// draw falling men
svg
  .selectAll('.fallingman')
  .data(myData)
  .enter()
  .append('svg')
  .attr('class', 'fallingman')
  .attr('viewBox', '0 0 960 700')
  .attr('width', '100')
  .attr('x', xMap)
  .attr('y', yMap)
  .append('path')
  .attr(
  'd',
  'M198 541.2c-.5-.5-.5-.9-.1-1.5 1.5-2.1 2.9-4.3 4.4-6.4.7-1 0-2.6-1.5-2.7-2.4-.2-4.7-.6-7.1.4-1.8.7-3.8 1.1-5.7 1.5-1.2.3-2.2-.3-2.1-1.3 0-.5.4-1.1.8-1.3 2-.9 4.1-1.6 6.2-2.4.5-.2 1-.4 1.5-.8.3-.3.5-.8.8-1.2-.4-.2-.9-.5-1.3-.6-.4-.1-.9.1-1.3.1l-5.7 1.2c-.6.1-1.1.4-1.7.6-1.1.4-1.9.2-2.3-.8-.4-1-.1-1.5 1.1-1.9 2.6-.8 5.1-1.4 7.7-2.2.5-.1 1.1-.2 1.5-.5s.6-.7.8-1.1c-.4-.2-.8-.7-1.2-.7-2.9-.1-5.8-.2-8.7.7-.8.2-1.4.1-1.6-.7-.2-.8.1-1.6 1-1.8 2.3-.5 4.5-1.2 6.8-1.3 3.2-.1 6.4.2 9.7.3.4 0 1.2-.2 1.3-.3.1-.7.3-1.6-.1-2.1-1.4-1.9-3.3-3.3-5.7-3.9-1.8-.5-2.8-1.7-3.5-3.3-.3-.7-.1-1.3.8-1.3s1.8 0 2.5.3c5.2 2.1 10.3 4.2 15.5 6.4 1.3.5 2.4 1.4 3.7 1.8 1.1.3 2.4.1 3.6-.1 1.1-.2 1.7.3 2.4 1.1 1.8 2.3 2.5 4.9 2.8 7.8v1.8c0 .7-.4 1-1.1 1.3-1.1.4-2.1 1-3 1.7-2.8 2.3-5.9 3.8-9.4 4.6-1.9.4-3.3 1.7-4.5 3.2-1.3 1.5-2.6 2.9-4 4.3-.5.5-1.2.9-1.8 1.3-.7-.2-1.1-.2-1.5-.2zm135.6-204c0 .4 0 .9-.1 1.3-.1 2.1 0 4.3-.5 6.3-.6 2.1-1.8 4-2.7 6-.4.8-.9 1.6-1.2 2.5-.5 1.4-.9 2.9-1.4 4.3-.1.4-.5.6-.8.9-.3-.3-.7-.7-.8-1-.2-.6-.1-1.3-.2-1.9-.4-2.8-.9-5.6-1.3-8.4 0-.2-.1-.3-.2-.4-.6-2.4-1.1-4.7-1.7-7.1-.7-2.8-1.2-5.5-1.2-8.4 0-.3-.2-.6-.2-.9-.6-2.3-1.2-4.5-1.8-6.8-.6-2.3-1.1-4.7-1.8-7.1-1.2-3.9-2.4-7.8-3.8-11.7-1.3-3.6-4.4-5-7.8-5.9-2.3-.6-4.3.6-6.3 1.3-1.2.4-2.2 1.3-3.3 2.1-1.7 1.2-3.6 2.2-5.2 3.6-2.1 1.8-4.4 2.7-7.1 2.6-2.2-.1-3.2-.9-3.6-3-.3-1.5-.2-3.1-1.1-4.5-.8-1.3-1.2-2.7-2-4-.8-1.4-2.2-2.3-3.6-3.1-2.2-1.3-5.2-.6-6.4 1.5-1.3 2.2-.8 4.7-.9 7.1-.2 4.4 1.6 8.6 2.1 12.9.2 1.9.9 3.8-.5 5.6-.2.2-.1.7-.1 1 .2 2.5.5 4.9.8 7.4.2 2 1.3 2.9 3.3 3 1.5.1 3 .3 4.4.2 1 0 2-.1 2.9-.5 1.9-.9 3.7-2.1 5.7-2.9 2.5-1 3.8-.2 3.7 2.6 0 1.4.4 2.7.8 4.1.4 1.6 1.1 3.2 1.3 4.8.4 4 .7 8 1 12 .1 1.9.3 3.8.4 5.7.1 1.9-2.8 4.1-4.6 3.5-.3-.1-.5-.3-.7-.6-.9-1-1.8-2-2.8-3-1.7-1.8-3.6-3.4-5.1-5.3-2.6-3.3-5.1-6.8-7.5-10.3-1.5-2.2-3-4.4-5.2-6-1.2-.8-2.3-1.7-3.4-2.6-.8-.7-1.4-1.5-2.1-2.3-1.3-1.3-2.7-2.5-3.8-4-1.6-2.2-2.6-4.6-3.5-7.2-2-5.9-4.2-11.8-6.4-17.6-.5-1.3-1-2.5-1.6-3.7-1.1-2.2-2.9-3.6-4.7-5.2-1.3-1.2-2.4-2.5-2.6-4.5-.3-2.6-.7-5.3-2-7.7-.6-1.1-.7-2.5-1.1-3.7-.1-.4-.4-1-.8-1.1-2-.5-2.4-2-2.5-3.6-.3-4.5-.4-8.9-.6-13.4 0-.5-.1-1-.2-1.5-.5-1.5-1.1-3-1.7-4.5-.6-1.4-2-2-3.5-1.6-3 1-5.8 2.3-8.3 4.3-3.2 2.6-4.9 5.8-3.9 9.9.4 1.8 1.1 3.5 1.8 5.3.5 1.3 1.1 2.5 1.7 3.7.8 1.7 1.6 3.4 2.6 4.9.6 1 .7 1.9.3 2.9-.2.5-.2 1.1 0 1.6.4 1.5.9 2.9 1.5 4.4.6 1.6 1.4 3.2 2.1 4.7.3.5.9.8 1.1 1.4.7 1.9 1.5 3.9 2 5.9.5 2.1.8 4.3 1.2 6.5.1.7.1 1.5.3 2.1 1.1 2.6 2.4 5 3.3 7.6 1 2.7 1.9 5.4 2.1 8.3.1 2 .8 4 1.4 6 .5 1.7 1.4 3.3 1.7 5.1.5 2.6.7 5.2 1.1 7.8.1.6.2 1.3.5 1.8 1.2 1.8 2.5 3.6 3.7 5.4 1.3 1.8 2.7 3.5 3.8 5.4.9 1.5 1.6 3.2 2.3 4.8 1 1.9 2 3.8 2.9 5.8 1 2.1 2.1 4.2 3.8 5.9.8.8.9 2 .3 2.6-1.1 1.4-1 2.9-1.1 4.4-.1 1.3-.1 2.8 1.1 3.9 1.2 1.1 2.4 2.2 3.5 3.4 2 2.1 4 4.2 6.1 6.2 3.1 3 6.4 5.7 9.2 9 2.9 3.3 5.2 7.1 7.8 10.7 1.6 2.2 3.2 4.5 4.9 6.7 2.3 2.8 4.8 5.4 7 8.2 2.3 3.1 3.2 6.7 3 10.5-.2 3.9-1.4 7.6-3 11.1-2.3 5-4.7 9.9-7.3 14.8-1.7 3.2-3.6 6.2-5.5 9.2-2.1 3.3-4.5 6.4-6.7 9.7-3.5 5.1-8.4 8.4-14.1 10.3-7.3 2.5-14.7 4.7-22.1 6.9-5 1.5-10.1 2.6-15.1 3.9-1.9.5-3.7.8-5.6 1.3-1.3.3-1.9 1.1-1.6 2.1.4 1.5 1.3.7 2.1.4 1.2-.4 2.6-.7 3.4.2 1.2 1.4 2.4 3 2.9 4.7 1 3.1 1.8 6.3 2.2 9.5.4 2.6 1 5.6-2.7 6.8-.8.3-.9 1.1-.1 1.6.5.3 1.1.6 1.6.6 1-.1 2.1-.4 3.1-.7 1.8-.6 3.5-1.4 5.2-2.1 13.2-5.2 26.7-9.4 39.3-16.1 3.5-1.9 6.9-3.8 10.3-5.9 2.6-1.6 4.9-3.4 7.4-5.1 2.3-1.6 4.6-3.2 6.8-4.9 2.8-2.1 5.6-4.3 8.4-6.5 3.1-2.4 5.9-5.1 7.9-8.4 1.1-1.8 2.4-3.6 3.7-5.3 2.6-3.3 6-5.6 9.5-7.8 1-.6 2-1.2 3.1-1.4 2.6-.5 5.2-.7 7.8-1.1.5-.1.9-.2 1.4-.4.8-.3 1.6-.7 2.4-1 1.2-.5 1.5-.2 2.1 1 .4.8 1 1.6 1.6 2.2.3.3 1 .3 1.4.6 2.3 2 4.4 4.2 7.2 5.6 1.7.9 3.3 2 5.4 1.9 1.8-.1 3.7 0 5.5 0 2.7 0 4.9-1 7-2.6 2.6-2 4.9-4.3 6.4-7.3 1.5-2.9 1.6-6 1.2-9.1-.2-1.5-.1-3.1-1.1-4.5-1-1.3-2-2.7-2.8-4.1-.3-.5-.4-1.5-.1-1.9 1.1-1.4 2.4-2.6 3.7-3.8 1.8-1.5 3.8-2.9 5.6-4.4 1.6-1.3 3.3-2.5 4.9-3.8 1.8-1.3 3.6-2.5 5.4-3.8s3.6-2.5 5.5-3.7c1.6-1 2.8-2.2 3.5-3.9.4-1.1.7-2.2 1.2-3.3 1-2.3 2-4.6 3.7-6.4 2.3-2.3 3.4-5.1 3.6-8.2.4-4.5 1.8-8.7 3.1-12.9 1-3.6 2.5-7 3.7-10.6.7-2.1 1.1-4.3 1.7-6.4.4-1.5 1.1-2.9 1.6-4.4.7-2.3.1-3.7-1.8-5.2-1.2-.9-2.4-1.7-3.8-2.3-2.6-1-5.2-2.1-8.1-2.2-.9-.1-1.5.3-1.8 1.2-.9 2.6-1.8 5.2-2.6 7.8-.4 1.1-.8 2.3-1.1 3.4-.8 2.8-1.6 5.7-2.2 8.5-.6 2.7-1.2 5.3-2.7 7.6-.9 1.3-1.8 2.7-2.5 4.2-.9 2.2-2 4.1-3.8 5.7-1.9 1.7-3.7 3.3-6.5 2.6-1.5-.3-2.9-.7-4.4-.8-4.2-.3-8.4-.8-12.3-2.4-1.7-.7-3.1-1.9-3.7-3.5-1-2.8-1.6-5.7-2.4-8.6s-1.5-5.9-2.3-8.8c-.3-1-.7-2-1.1-3-.6-1.2-1.2-2.4-1.9-3.7-1.2-2.4-2.3-5-3.7-7.3-1.7-2.8-3.5-5.6-5.5-8.2-2.5-3.3-5.3-6.5-8-9.6-2.6-2.9-5.1-5.9-6.3-9.7-.1-.3-.4-.6-.6-.9.5.1.3.1.2.2zm-3.6 48.5c2.7 1.4 4.9 3.6 7 5.6 1.7 1.7 3.3 3.5 5.4 4.7 2 1.2 4.5 1.8 6.8 2.5 1.6.5 3.2.9 4.8 1.4.9.3 1.7.6 2.6.8 1.5.4 2.2 1.3 2.1 2.8-.2 4.1.3 8.1 1.4 12 1.3 4.8 2.7 9.5 4 14.3.6 2.2 1.1 4.5 1.7 6.8-2.7-.3-4.9-2.2-5.6-4.4-.3-.9-.8-1.8-1.3-2.7-.5-.7-2.1-.8-2.8-.1-.8.7-1.6.8-2.6.5-3-.7-5.9-1.4-8.8-2.1-1-.2-1.9-.6-2.1-1.7-.2-1.6-1.2-2.7-2.3-3.4-1.5-1-2.2-2.4-2.8-3.9-1.7-4.2-3.3-8.5-4.9-12.7-1.3-3.5-2.7-7.1-3.9-10.7-1.2-3.4-2.1-6.9-2.6-10.5.1-.1.2-.3.3-.4 1.2.4 2.5.6 3.6 1.2zm-8.4 9.9c1.3 3.8 2.6 7.5 4.3 11.1 2.2 4.6 4.8 8.9 8.1 12.8.8.9 1.6 1.7 2.3 2.7.3.5.3 1.3.3 1.9 0 .9-.2 1.8-.1 2.7 0 1.2-.2 2.2-.8 3.4-.7 1.2-1.4 2.5-.9 4.2.3 1.1 0 2.3.1 3.5.1 1.5.2 3 .3 4.6-1.3-.3-2.1-.8-2.5-2-1.3-3.1-2.7-6.2-4.1-9.3-1.4-3-2.9-6-4.4-9-1.2-2.3-3.1-3.9-5.2-5.3l-13.8-9c-.8-.5-1.6-1.1-2.4-1.5-1.6-.8-1.7-2.6-2.6-3.8-1.3-1.9-2.8-3.8-4.3-5.6-.5-.6-.6-1-.1-1.6.4-.5.7-1.2 1-1.8.9-1.6 2.2-2.7 3.8-3.6 4.3-2.4 8.8-4.4 13.7-4.9.5-.1 1-.3 1.5-.5.9-.2 1.7-.4 2.6-.7 1 4.1 2 7.9 3.2 11.7zm92.2-43.3c-.1.3-.5.8-.7.9-1.8.2-3.7.3-5.1-1.3-.3-.3-.8-.6-1.2-.6-.4 0-.9.2-1.1.5-.2.2-.2.8 0 1.1 1 1.6 1.9 3.2 3.1 4.5 1.5 1.7 3.1 3 5.7 3 2.5 0 4.9 1.2 6.9 3 .7.7 1.2.7 1.9 0 2-1.9 3.4-4.1 3.4-6.9 0-2.3 1-4 2.3-5.6.2-.2.5-.4.5-.7.1-.5 0-.9-.1-1.4-.4 0-1-.1-1.3.2-.7.4-1.2 1.1-1.8 1.5-.5.3-1.2.2-1.8.2 0-.4-.1-.9 0-1.3s.3-.7.4-1.1c.1-1.1.2-2.1 0-3.2-.1-.4-.8-.6-1.2-.9-.3.4-.7.8-.8 1.3-.2.6-.2 1.4-.5 1.9-.2.4-.8.6-1.2.9-.2-.4-.6-.9-.5-1.3.1-1.7-.4-3.1-1.9-3.9-.4-.2-.9-.2-1.3-.3-.1.4-.3.9-.2 1.3.2.8.7 1.6.9 2.5.1.5-.1 1.1-.2 1.6-.5-.3-1.1-.6-1.6-1-.1-.1-.1-.3-.2-.4-1.1-1.2-1.7-3-3.4-3.5-.5-.1-1 0-1.5 0 .1.5.2 1 .4 1.4 1.2 1.9 2.7 3.7 2.5 6.1-.4.5-.3 1.1-.4 1.5z'
);

Код здесь https://codepen.io/kylehagler/pen/VxPqyM

1 Ответ

0 голосов
/ 01 мая 2018

Проблема здесь в 2 раза:

  • сначала ваши дочерние svg размещаются по умолчанию в xMidYMid, что означает, что в зависимости от их ширины и высоты браузер попытается изменить положение окна просмотра, что создаст впечатление, что координаты x и y не соблюдаются.
  • секунда, путь, который вы определяете в viewBox дочернего svg, 0 0 960 700 смещен, это означает, что даже если вы расположите верхний левый угол svg, путь все равно будет смещен (потому что он не начинается с 0).

Чтобы исправить это, во-первых, нам нужно убедиться, что мы контролируем размеры svg с помощью preserveAspectRatio, а во-вторых, мы добавим атрибут пути translate, чтобы сделать его как можно ближе к источнику его родителя. Итак, вкратце замените часть вашего скрипта следующим:

svg
  .selectAll('.fallingman')
  .data(myData)
  .enter()
  .append('svg')
  .attr('class', 'fallingman')
  .attr('viewBox', '0 0 960 700')
  .attr("preserveAspectRatio","none")//we control how the viewport is positioned
  .attr('width', '96')
  .attr("height","70")
  .attr('x', xMap)
  .attr('y', yMap)
  .append('path')
  .attr("transform","translate(-200,-250)")//move the path to origin
  .attr(
  'd',...
...