2013-04-25 3 views
0

plotI'm новичок в d3 и довольно новичок в javascript (большая часть моего опыта связана с python). Недавно я прочитал учебник в книге Интерактивная визуализация данных: для сети Скотта Мюррея по созданию гистограммы. У меня не было проблем с завершением учебника, но подход, который он использует в книге, по-видимому, в основном процедурный, используя глобальные переменные. Я хотел бы создать аналогичную диаграмму, но использовать объектно-ориентированный подход, чтобы иметь возможность инкапсулировать переменные и повторно использовать код для генерации нескольких диаграмм в одном скрипте, не повторяя код снова и снова. Это то, что я пытался до сих пор без везения:пытается создать гистограмму в d3 с использованием объектно-ориентированного подхода

 function d3Chart(id, data, width, height, padding) { 
      this.id = id 
      this.data = data 
      this.width = width 
      this.height = height 
      this.padding = padding 
      this.svg = d3.select("body") 
       .append("svg") 
       .attr("width", width) 
       .attr("height", height) 
       .attr("class", "chart") 
       .attr("id". this.id); 
      this.yscale = d3.scale.linear() 
       .domain([0, d3.max(data)]) 
       .range([h - padding, padding]) 
      this.xscale = d3.scale.ordinal() 
       .domain(d3.range(data.length)) 
       .rangeRoundBands([padding,w-padding], 0.05) 
     }; 

     d3Chart.prototype.rect = function() { 

      this.rect = this.svg.selectAll("rect") 
       .data(this.data) 
       .enter() 
       .append("rect"); 
     } 

     d3Chart.prototype.plot = function() { 

      this.rect.attr("x", function(d, i) { 
        return this.xscale(i); 
       }) 
       .attr("y", function (d) { 
        return this.yscale(d); 
       }) 
       .attr("width", this.xscale.rangeBand()) 
       .attr("height", function(d) { 
        return this.height - this.padding - this.yscale(d); 
       }) 
       .attr("fill", function(d) { 
        return "rgb(" + (100 - d) + ", 0, " + (d*10) + ")"; 
       }); 
      } 

     var chart = new d3Chart("chart1", [5, 15, 10, 30, 20, 45, 15, 10, 5], 600, 400, 40); 
     chart.rect() 
     chart.plot() 

я уверен, что есть что-то очень простое, что я делаю неправильно, кто-нибудь знает, почему это не работает, или, если это даже правильный подход? Любая помощь приветствуется. Благодарю.

+0

Дмитрий Сошников написал очень [короткое, но сладкое описание] (http://dmitrysoshnikov.com/ecmascript/javascript-the-core/) механики Javascript, которую стоит прочитать. Большинство из вас, ООП, вероятно, могут быть решены путем возврата функции внутри функции, которая имеет переменные, установленные и зафиксированные в закрытии, инкапсуляции. Если вам нужно расширить базовый объект, просмотрите методы [Object.create] (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create) и Object.defineProperty. –

ответ

1

Первая проблема с вашим кодом заключается в том, что у вас есть пара опечаток, например. . вместо , и h вместо height. Вторая проблема заключается в том, что вы делаете все атрибутом this, который будет отличаться в разных контекстах. Например, в

this.rect.attr("x", function(d, i) { 
       return this.xscale(i); 
      }) 

два this относятся к разным объектам - во втором случае this является фактическим DOM элемент вы работаете, и не имеет атрибута вы имеете в виду.

Так что вам нужно сохранить все атрибуты глобального объекта, например window. Это, конечно, не намного лучше, чем использование глобальных переменных. Для более объектно-ориентированного подхода вам потребуется создать объект, который содержит всю информацию и передать его, или реализовать методы, которые вы можете вызвать на нем.

Я поставил ваш фиксированный код в jsfiddle here.

+0

Спасибо, это очень полезно. Как я уже сказал, я новичок в javascript, поэтому я все еще испытываю трудное время, обдумывая ключевое слово «это». –

+0

, который вы говорите: «Для более объектно-ориентированного подхода вам необходимо создать объект, который содержит всю информацию и передать его, или реализовать методы, которые вы можете вызвать на нем». у вас есть более конкретный пример этого. могу ли я привязать переменные к элементу svg, а не к «окну»? –

+0

То, что я говорю, это то, что вы создадите пользовательский объект (то есть просто общий объект) для использования для атрибутов. Неправильная привязка переменных к элементу SVG не является хорошей идеей. –

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