SVG не рендерится как базовый вид - PullRequest
21 голосов
/ 11 марта 2012

Я использую d3.js для рендеринга карты мира в SVG (используя https://github.com/johan/world.geo.json/blob/master/countries.geo.json для функций). Я инкапсулирую логику рендеринга в Backbone View. Когда я отображаю представление и присоединяю его к DOM, в моем браузере ничего не отображается, хотя разметка SVG генерируется правильно при просмотре сгенерированного HTML. Это прекрасно, когда не инкапсулирует в Backbone.View. Вот мой код с использованием Backbone.view:

/**
 * SVG Map view
 */
var MapView = Backbone.View.extend({
    tagName: 'svg',
    translationOffset: [480, 500],
    zoomLevel: 1000,

    /**
     * Sets up the map projector and svg path generator
     */
    initialize: function() {
        this.projector = d3.geo.mercator();
        this.path = d3.geo.path().projection(this.projector);
        this.projector.translate(this.translationOffset);
        this.projector.scale(this.zoomLevel);
    },

    /**
     * Renders the map using the supplied features collection
     */
    render: function() {
        d3.select(this.el)
          .selectAll('path')
          .data(this.options.featureCollection.features)
          .enter().append('path')
          .attr('d', this.path);
    },

    /**
     * Updates the zoom level
     */
    zoom: function(level) {
        this.projector.scale(this.zoomLevel = level);
    },

    /**
     * Updates the translation offset
     */
    pan: function(x, y) {
        this.projector.translate([
            this.translationOffset[0] += x,
            this.translationOffset[1] += y
        ]);
    },

    /**
     * Refreshes the map
     */
    refresh: function() {
        d3.select(this.el)
          .selectAll('path')
          .attr('d', this.path);
    }
});

var map = new MapView({featureCollection: countryFeatureCollection});
map.$el.appendTo('body');
map.render();

Вот код, который работает, без использования Backbone.View

var projector = d3.geo.mercator(),
    path = d3.geo.path().projection(projector),
    countries = d3.select('body').append('svg'),
    zoomLevel = 1000;

coords = [480, 500];
projector.translate(coords);
projector.scale(zoomLevel);

countries.selectAll('path')
         .data(countryFeatureCollection.features)
         .enter().append('path')
         .attr('d', path);

Я также приложил скриншот сгенерированной разметки SVG. Есть идеи, что здесь может пойти не так?

enter image description here

Edit - вот переопределенный метод make, который в итоге решил эту проблему для каждого запроса:

/**
 * Custom make method needed as backbone does not support creation of
 * namespaced HTML elements.
 */
make: function(tagName, attributes, content) {
    var el = document.createElementNS('http://www.w3.org/2000/svg', tagName);
    if (attributes) $(el).attr(attributes);
    if (content) $(el).html(content);
    return el;
}

Ответы [ 3 ]

27 голосов
/ 11 марта 2012

Проблема в том, что элементу "svg" требуется пространство имен. D3 делает это для вас автоматически; когда вы добавляете элемент "svg", он использует пространство имен "http://www.w3.org/2000/svg". Подробнее см. src / core / ns.js . Backbone, к сожалению, не поддерживает элементы пространства имен. Вам нужно изменить метод view.make * 1006. * Затем вам понадобится свойство namespaceURI в вашем представлении, чтобы установить соответствующее пространство имен, или просто сделать это автоматически для элементов SVG для согласованности с анализатором HTML5.

В любом случае, простое решение вашей проблемы - обернуть SVG в элемент DIV, а затем использовать D3 для создания элемента SVG.

4 голосов
/ 23 июля 2012

Вы можете просто установить элемент представления в функции инициализации следующим образом:

Backbone.View.extend({
    // This is only for informaiton. The node will
    // be raplaced in the initialize function.
    tagName: 'svg',

    initialize: function () {
        this.setElement(
            d3.select($('<div/>')[0]).append('svg')[0]
        );
    }
);

Преимущество в том, что он явный.

3 голосов
/ 12 октября 2013

Проверьте это http://jsfiddle.net/nocircleno/QsEp2/ из http://nocircleno.com/blog/svg-with-backbone-js/

Backbone.View.extend({
  nameSpace: "http://www.w3.org/2000/svg",
  _ensureElement: function() {
     if (!this.el) {
        var attrs = _.extend({}, _.result(this, 'attributes'));
        if (this.id) attrs.id = _.result(this, 'id');
        if (this.className) attrs['class'] = _.result(this, 'className');
        var $el = $(window.document.createElementNS(_.result(this, 'nameSpace'), _.result(this, 'tagName'))).attr(attrs);
        this.setElement($el, false);
     } else {
        this.setElement(_.result(this, 'el'), false);
     }
 }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...