Работа с полигональными элементами SVG

Я пытаюсь работать с полигоном SVG и javascript. Я создаю многоугольник и устанавливаю его начальный список точек следующим образом:

var polygon = document.createElementNS('http://www.w3.org/2000/svg','polygon');
polygon.setAttribute("points", "0,0  100,100 200,200");

что мне теперь делать, если я хочу изменить 2-ю точку (100 100)? Прямо сейчас я в основном реконструирую всю строку снова. Но можем ли мы каким-то образом обращаться к «polygon.points» как к массиву, или это действительно простая строка? Это может работать нормально для очень простых многоугольников, но если мой многоугольник в конечном итоге будет иметь сотни пар точек, мне бы не хотелось реконструировать весь атрибут «точки» в виде строки каждый раз, когда я хочу изменить один элемент.

Спасибо


person user246114    schedule 28.01.2010    source источник


Ответы (4)


Боюсь, никак не обойти это. Вы должны восстановить строку снова. Но нетрудно обернуть все это в объект, например:

function Polygon () {
    var pointList = [];
    this.node = document.createElementNS('http://www.w3.org/2000/svg','polygon');
    function build (arg) {
        var res = [];
        for (var i=0,l=arg.length;i<l;i++) {
            res.push(arg[i].join(','));
        }
        return res.join(' ');
    }
    this.attribute = function (key,val) {
        if (val === undefined) return node.getAttribute(key);
        node.setAttribute(key,val);
    }
    this.getPoint = function (i) {return pointList[i]}
    this.setPoint = function (i,x,y) {
        pointList[i] = [x,y];
        this.attribute('points',build(pointList));
    }
    this.points = function () {
      for (var i=0,l=arguments.length;i<l;i+=2) {
          pointList.push([arguments[i],arguments[i+1]]);
      }
      this.attribute('points',build(pointList));
    }
    // initialize 'points':
    this.points.apply(this,arguments);
}

var polygon = new Polygon(0,0, 100,100, 200,200);
polygon.setPoint(0, 50,10); // set point and automatically re-build points
polygon.points(50,50, 50,100, 200,100); // set everything
polygon.node; // refer to the actual SVG element

* не лучшая реализация, но вы поняли.

person slebetman    schedule 28.01.2010
comment
Спасибо, выглядит здорово, я понимаю, что вы имеете в виду. Я попытаюсь реализовать оптимизированное представление поверх «ванильного». - person user246114; 28.01.2010
comment
Если я запускаю этот код в Chrome 58, я получаю сообщение об ошибке Uncaught ReferenceError: узел не определен. Это происходит только в консоли разработчика Chrome, поэтому я думаю, что это присуще коду. - person Colin D; 07.06.2017
comment
@ColinD Должно быть this.node. Этот код никогда не предназначался для использования как есть. Это иллюстрирует идею о том, что вы можете легко реализовать код для управления полигонами самостоятельно. - person slebetman; 07.06.2017

Вы можете получить доступ к значениям отдельных точек, используя SVG DOM:

var p = polygon.points.getItem(1);
p.x = 150;
p.y = 300;

(При условии, что ваш UA реализует этот интерфейс.) См. SVGPolygonElement, SVGAnimatedPoints, SVGPointList и SVGPoint.

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

person heycam    schedule 28.01.2010

Вам нужно использовать setAttributeNS. Вы, вероятно, захотите кэшировать это пространство имен где-нибудь в переменной, чтобы вам не приходилось постоянно его вводить.

person Kyle Butt    schedule 28.01.2010
comment
Должны ли мы использовать setAttributeNS/getAttributeNS всякий раз, когда мы устанавливаем атрибут с элементом SVG? Например, даже если мы хотим изменить параметр «x» прямоугольника? (rect.setAttributeNS(ns, 'x', 22)? Спасибо. - person user246114; 28.01.2010

Вам нужно установить все точки сразу, производительность довольно стабильная, что вы можете сделать, это управлять массивом снаружи и объединять его в вызовах setAttribute.

person Don Albrecht    schedule 28.01.2010
comment
Итак, если мне нужно общее решение, чтобы изменить N-ю пару, мне нужно самому проанализировать строку, найти ее, а затем изменить. Это воняет, но, думаю, я могу сохранить пары точек как отдельную структуру, воняет, что они так сделали! Спасибо - person user246114; 28.01.2010