Вставить ссылки на данные api в Google Charts?

Я немного поиграл с диаграммами Google на игровой площадке Google Maps:

Ссылка

Код, с которым я играл, это:

function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['Year', 'Austria'],
    ['2003',  1336060],
    ['2004',  1538156],
    ['2005',  1576579],
    ['2006',  1600652],
    ['2007',  1968113],
    ['2008',  1901067]
  ]);

  // Create and draw the visualization.
  new google.visualization.BarChart(document.getElementById('visualization')).
      draw(data,
           {title:"Yearly Coffee Consumption by Country",
            width:600, height:400,
            vAxis: {title: "Year"},
            hAxis: {title: "Cups"}}
      );
}

и это дает мне хорошую диаграмму, которая выглядит так:

enter image description here

Я пытаюсь, чтобы эта диаграмма соответствовала потребностям моего веб-сайта, и для этого мне нужно сделать имена баров слева на другой странице. Так, например, в 2003 году была бы ссылка, которую пользователь может щелкнуть мышью так, как и в 2004 году.

Я попытался сделать что-то вроде этого:

function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['Year', 'Austria'],
    ['<a href="url">Link text</a>',  1336060],
    ['2004',  1538156],
    ['2005',  1576579],
    ['2006',  1600652],
    ['2007',  1968113],
    ['2008',  1901067]
  ]);

  // Create and draw the visualization.
  new google.visualization.BarChart(document.getElementById('visualization')).
      draw(data,
           {title:"Yearly Coffee Consumption by Country",
            width:600, height:400,
            vAxis: {title: "Year"},
            hAxis: {title: "Cups"}}
      );
}

Но я мог только надеяться, что это будет так просто, и это не так. Кто-нибудь знает, возможно ли это?

Ответ 1

Это нетривиально, потому что вывод, который вы видите, - это SVG, а не HTML. Эти метки в вашем примере ( "2004", "2005" и т.д.) Встроены в текстовые узлы SVG, поэтому вставка необработанной HTML-разметки внутри них не будет отображаться как HTML.

Обходной путь - сканировать текстовые узлы, содержащие целевые значения (опять же, "2004", "2005" и т.д.) и заменить их на ForeignObject, Элементы ForeignObject могут содержать обычный HTML. Затем они должны быть размещены больше или меньше, где были оригинальные текстовые узлы SVG.

Вот пример фрагмента, иллюстрирующий все это. Он настроен на ваш конкретный пример, поэтому, когда вы переключаетесь на рендеринг любых ваших реальных данных, вы захотите соответствующим образом изменить и обобщить этот фрагмент.

// Note: You will probably need to tweak these deltas
// for your labels to position nicely.
var xDelta = 35;
var yDelta = 13;
var years = ['2003','2004','2005','2006','2007','2008'];
$('text').each(function(i, el) {
  if (years.indexOf(el.textContent) != -1) {
    var g = el.parentNode;
    var x = el.getAttribute('x');
    var y = el.getAttribute('y');
    var width = el.getAttribute('width') || 50;
    var height = el.getAttribute('height') || 15;

    // A "ForeignObject" tag is how you can inject HTML into an SVG document.
    var fo = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject")
    fo.setAttribute('x', x - xDelta);
    fo.setAttribute('y', y - yDelta);
    fo.setAttribute('height', height);
    fo.setAttribute('width', width);
    var body = document.createElementNS("http://www.w3.org/1999/xhtml", "BODY");
    var a = document.createElement("A");
    a.href = "http://yahoo.com";
    a.setAttribute("style", "color:blue;");
    a.innerHTML = el.textContent;
    body.appendChild(a);
    fo.appendChild(body);

    // Remove the original SVG text and replace it with the HTML.
    g.removeChild(el);
    g.appendChild(fo);
  }
});

Незначительное примечание: для удобства есть немного jQuery, но вы можете заменить $('text') на document.getElementsByTagName("svg")[0].getElementsByTagName("text").

Ответ 2

Манзоидный ответ хорош, но "какая-то сборка по-прежнему требуется", поскольку она просто отображает окно предупреждения, а не ссылку. Вот более полный ответ, но он делает штрихи кликабельными, а не ярлыками. Я создаю DataTable, который включает ссылки, затем создайте DataView, чтобы выбрать столбцы Я хочу отобразить. Затем, когда происходит событие select, я просто извлекаю ссылку из исходного DataTable.

<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Year', 'link', 'Austria'],
          ['2003', 'http://en.wikipedia.org/wiki/2003',  1336060],
          ['2004', 'http://en.wikipedia.org/wiki/2004', 1538156],
          ['2005', 'http://en.wikipedia.org/wiki/2005', 1576579],
          ['2006', 'http://en.wikipedia.org/wiki/2006', 1600652],
          ['2007', 'http://en.wikipedia.org/wiki/2007', 1968113],
          ['2008', 'http://en.wikipedia.org/wiki/2008', 1901067]             
        ]);
       var view = new google.visualization.DataView(data);
       view.setColumns([0, 2]);

       var options = {title:"Yearly Coffee Consumption by Country",
            width:600, height:400,
            vAxis: {title: "Year"},
            hAxis: {title: "Cups"}};

       var chart = new google.visualization.BarChart( 
           document.getElementById('chart_div'));
       chart.draw(view, options);

       var selectHandler = function(e) {
          window.location = data.getValue(chart.getSelection()[0]['row'], 1 );
       }

       google.visualization.events.addListener(chart, 'select', selectHandler);
      }
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 900px; height: 900px;"></div>
  </body>
</html>

Ответ 3

Поскольку маршрут SVG-внедрения (по понятным причинам) слишком волосатый, чтобы вы захотели гадать, попробуйте совершенно другой подход. Предполагая, что у вас есть гибкость, чтобы немного изменить функциональную спецификацию, чтобы бары были интерактивными, а не ярлыками, то здесь гораздо более простое решение, которое будет работать.

Ищите alert в этом фрагменте, часть, которую вы настроите для перенаправления.

function drawVisualization() {
  // Create and populate the data table.
  var rawData = [
    ['Year', 'Austria'],
    ['2003',  1336060],
    ['2004',  1538156],
    ['2005',  1576579],
    ['2006',  1600652],
    ['2007',  1968113],
    ['2008',  1901067]
  ];
  var data = google.visualization.arrayToDataTable(rawData);

  // Create and draw the visualization.
  var chart = new google.visualization.BarChart(document.getElementById('visualization'));
  chart.draw(data,
           {title:"Yearly Coffee Consumption by Country",
            width:600, height:400,
            vAxis: {title: "Year"},
            hAxis: {title: "Cups"}}
      );
  var handler = function(e) {
    var sel = chart.getSelection();
    sel = sel[0];
    if (sel && sel['row'] && sel['column']) {
      var year = rawData[sel['row'] + 1][0];
      alert(year); // This where you'd construct the URL for this row, and redirect to it.
    }
  }
  google.visualization.events.addListener(chart, 'select', handler);
}

Ответ 4

У меня, по-видимому, недостаточно очков репутации, чтобы прокомментировать предыдущий ответ, поэтому я извиняюсь за то, что сделал это как новое сообщение. манцоидское внушение велико, но есть одна проблема, которую я нашел, и похоже, что Марк Батлер, возможно, столкнулся с той же проблемой (или неосознанно обошел ее).

if (sel && sel['row'] && sel['column']) {

Эта строка не позволяет клиенту использовать первую точку данных. Я использовал его на графике в январе-декабре, и только февраль-декабрь был доступен для просмотра. Удаление sel ['row'] из условия позволяет Jan работать. Я не знаю, что условие if() действительно даже необходимо.

Ответ 5

Вы должны использовать formatters.

Если вы замените значение на HTML, сортировка не будет работать должным образом.

Ответ 6

Здесь другое решение, которое обертывает каждый текстовый тег для метки тегом привязки.

  • no ForeignObject
  • clickable label
  • stylable css (эффект зависания)

Здесь пример: https://jsfiddle.net/tokkonoPapa/h3eq9m9p/

/* find the value in array */
function inArray(val, arr) {
    var i, n = arr.length;
    val = val.replace('…', ''); // remove ellipsis
    for (i = 0; i < n; ++i) {
        if (i in arr && 0 === arr[i].label.indexOf(val)) {
            return i;
        }
    }
    return -1;
}

/* add a link to each label */
function addLink(data, id) {
    var n, p, info = [], ns = 'hxxp://www.w3.org/1999/xlink';

    // make an array for label and link.
    n = data.getNumberOfRows();
    for (i = 0; i < n; ++i) {
        info.push({
            label: data.getValue(i, 0),
            link:  data.getValue(i, 2)
        });
    }

    $('#' + id).find('text').each(function(i, elm) {
        p = elm.parentNode;
        if ('g' === p.tagName.toLowerCase()) {
            i = inArray(elm.textContent, info);
            if (-1 !== i) {
                /* wrap text tag with anchor tag */
                n = document.createElementNS('hxxp://www.w3.org/2000/svg', 'a');
                n.setAttributeNS(ns, 'xlink:href', info[i].link);
                n.setAttributeNS(ns, 'title', info[i].label);
                n.setAttribute('target', '_blank');
                n.setAttribute('class', 'city-name');
                n.appendChild(p.removeChild(elm));
                p.appendChild(n);
                info.splice(i, 1); // for speeding up
            }
        }
    });
}

function drawBasic() {
    var data = google.visualization.arrayToDataTable([
        ['City', '2010 Population', {role: 'link'}],
        ['New York City, NY', 8175000, 'hxxp://google.com/'],
        ['Los Angeles, CA',   3792000, 'hxxp://yahoo.com/' ],
        ['Chicago, IL',       2695000, 'hxxp://bing.com/'  ],
        ['Houston, TX',       2099000, 'hxxp://example.com'],
        ['Philadelphia, PA',  1526000, 'hxxp://example.com']
    ]);

    var options = {...};
    var chart = new google.visualization.BarChart(
        document.getElementById('chart_div')
    );

    chart.draw(data, options);

    addLink(data, 'chart_div');
}