Динамически добавленные дочерние элементы к элементу svg-pan-zoom не выполняют панорамирование / масштабирование, но ранее добавленные элементы делают

Я создаю объект svg с помощью javascript, рисую базовый треугольник Серпинского, а затем устанавливаю объект svg как svg-pan-zoom. При масштабировании за порогом я пытаюсь перерисовать следующий уровень треугольников, который я вижу на экране, но они не реагируют на масштабирование или панорамирование.

В настоящее время я пытаюсь повторно применить svg-pan-zoom к объекту после рисования следующего уровня треугольников, но это, похоже, не работает.

HTML в основном пустое тело.

Код JS, о котором идет речь:

var width = 300;
var height = 300;
var length;
var maxDepth = 5;
var depth = 0;
var svg;
var div;
//2D array of triangles, where first index is their recursive depth at an offset
var triangles;
var zoomCount = 0;

$(document).ready(function () {
    //init();



    var ns = 'http://www.w3.org/2000/svg'
    div = document.getElementById('drawing')
    svg = document.createElementNS(ns, 'svg')
    svg.setAttributeNS(null, 'id', 'svg-id')
    svg.setAttributeNS(null, 'width', '100%')
    svg.setAttributeNS(null, 'height', '100%')
    div.appendChild(svg)

    /*var rect = document.createElementNS(ns, 'rect')
    rect.setAttributeNS(null, 'width', 100)
    rect.setAttributeNS(null, 'height', 100)
    rect.setAttributeNS(null, 'fill', '#f06')
    svg.appendChild(rect)*/

    init();

    enableZoomPan();

});

function init() {

    triangles = create2DArray(5);

    //Calculate triangle line length
    length = height/Math.sin(60*Math.PI/180)    //Parameter conversion to radians

    t = new Triangle(new Point(0, height), new Point(width, height), new Point(width/2, 0));
    sketchTriangle(t);
    //Recursively draw children triangles
    drawSubTriangles(t, true);
    attachMouseWheelListener();

}

function enableZoomPan() {
    //Enable zoom/pan
    var test = svgPanZoom('#svg-id', {
        zoomEnabled: true,
        controlIconsEnabled: false,
        fit: true,
        center: true,
        minZoom: 0
    });
}

function attachMouseWheelListener() {
    if (div.addEventListener)
    {
        // IE9, Chrome, Safari, Opera
        div.addEventListener("mousewheel", MouseWheelHandler, false);
        // Firefox
        div.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
    }
// IE 6/7/8
    else
    {
        div.attachEvent("onmousewheel", MouseWheelHandler);
    }

    function MouseWheelHandler(e)
    {
        // cross-browser wheel delta
        var e = window.event || e; // old IE support
        //Delta +1 -> scrolled up
        //Delta -1 -> scrolled down
        var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
        console.log(delta);

        zoomCount = zoomCount + delta;

        if(zoomCount==15) {

            for(var i = 0; i < triangles[0].length; i++) {
                drawSubTriangles(triangles[0][i], false);
            }
            enableZoomPan();
        }

        return false;
    }
}


function drawLine(p1, p2) {

    var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
    line.setAttribute('x1', p1.x);
    line.setAttribute('y1', p1.y);
    line.setAttribute('x2', p2.x);
    line.setAttribute('y2', p2.y);
    line.setAttribute('stroke', "black");
    line.setAttribute('stroke-width', 1);
    svg.appendChild(line);

}

//Recursive parameter if you want to draw recursively, or just stop after one level
function drawSubTriangles(t, recursive) {
    //End condition, bounded by maximum recursion depth
    if(depth == maxDepth && recursive==true) {
        //Push triangle to depth collection, to track in case zooming in and redrawing
        triangles[maxDepth-depth].push(t);
        return;
    }

    depth = depth + 1;

    //Sub triangle lengths are half of parent triangle
    subLength = length/depth;

    var midPoint1 = getCenter(t.p1, t.p2);
    var midPoint2 = getCenter(t.p2, t.p3);
    var midPoint3 = getCenter(t.p3, t.p1);

    midTriangle = new Triangle(midPoint1, midPoint2, midPoint3);

    sketchTriangle(midTriangle)

    //Recursive call to continue drawing children triangles until max depth
    if(recursive == true) {
        drawSubTriangles(new Triangle(t.p1, midPoint1, midPoint3), true);
        drawSubTriangles(new Triangle(midPoint3, midPoint2, t.p3), true);
        drawSubTriangles(new Triangle(midPoint1, t.p2, midPoint2), true);
    }
    depth = depth -1;
}



function sketchTriangle(t) {
    drawLine(t.p1, t.p2);
    drawLine(t.p2, t.p3);
    drawLine(t.p3, t.p1);
}

function create2DArray(rows) {
    var arr = [];

    for (var i=0;i<rows;i++) {
        arr[i] = [];
    }

    return arr;
}

function getCenter(p1, p2) {
    return new Point((p1.x + p2.x)/2, (p1.y + p2.y)/2);
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}

function Triangle(p1, p2, p3) {
    this.p1 = p1;
    this.p2 = p2;
    this.p3 = p3;
}

1 ответ

Решение

По какой-то причине svg-pan-zoom оборачивает весь ваш SVG-контент внутри <g> элемент. Панорамирование и масштабирование затем достигается путем изменения transform атрибут, связанный с этим элементом. Таким образом, при первом взаимодействии с SVG его структура меняется следующим образом:

<svg>
  <line ...>
  <line ...>
  ...
</svg>

к этому:

<svg>
  <g transform="matrix(1 0 0 1 0 0)">
    <line ...>
    <line ...>
    ...
  </g>
</svg>

Когда вы добавляете больше элементов к чертежу, они добавляются к корню <svg> элемент. В результате они вообще не трансформируются.

Вы можете исправить это достаточно легко. Просто оберните свой рисунок внутри <g> элемент перед вызовом svg-pan-zoom. Затем он будет использовать этот элемент вместо добавления своего. При добавлении к чертежу добавьте новые объекты к этому элементу.

Вот ваш код с очень незначительными изменениями:

var width = 300;
var height = 300;
var length;
var maxDepth = 5;
var depth = 0;
var svg;
var svgg;  /* Top <g> element inside svg */
var div;

//2D array of triangles, where first index is their recursive depth at an offset
var triangles;
var zoomCount = 0;

$(document).ready(function () {
    //init();

    var ns = 'http://www.w3.org/2000/svg'
    div = document.getElementById('drawing')
    svg = document.createElementNS(ns, 'svg')
    svg.setAttributeNS(null, 'id', 'svg-id')
    svg.setAttributeNS(null, 'width', '100%')
    svg.setAttributeNS(null, 'height', '100%')
    svgg = document.createElementNS(ns, 'g')
    svg.appendChild(svgg)
    div.appendChild(svg)

    init();
    enableZoomPan();
});

function init() {

    triangles = create2DArray(5);

    //Calculate triangle line length
    length = height/Math.sin(60*Math.PI/180)    //Parameter conversion to radians

    t = new Triangle(new Point(0, height), new Point(width, height), new Point(width/2, 0));
    sketchTriangle(t);
    //Recursively draw children triangles
    drawSubTriangles(t, true);
    attachMouseWheelListener();

}

function enableZoomPan() {
    //Enable zoom/pan
    var test = svgPanZoom('#svg-id', {
        zoomEnabled: true,
        controlIconsEnabled: false,
        fit: true,
        center: true,
        minZoom: 0
    });
}

function attachMouseWheelListener() {
    if (div.addEventListener)
    {
        // IE9, Chrome, Safari, Opera
        div.addEventListener("mousewheel", MouseWheelHandler, false);
        // Firefox
        div.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
    }
// IE 6/7/8
    else
    {
        div.attachEvent("onmousewheel", MouseWheelHandler);
    }

    function MouseWheelHandler(e)
    {
        // cross-browser wheel delta
        var e = window.event || e; // old IE support
        //Delta +1 -> scrolled up
        //Delta -1 -> scrolled down
        var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
        zoomCount = zoomCount + delta;
        if(zoomCount==15) {
            for(var i = 0; i < triangles[0].length; i++) {
                drawSubTriangles(triangles[0][i], false);
            }
            enableZoomPan();
        }
        return false;
    }
}


function drawLine(p1, p2) {

    var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
    line.setAttribute('x1', p1.x);
    line.setAttribute('y1', p1.y);
    line.setAttribute('x2', p2.x);
    line.setAttribute('y2', p2.y);
    line.setAttribute('stroke', "black");
    line.setAttribute('stroke-width', 1);
    svgg.appendChild(line);

}

//Recursive parameter if you want to draw recursively, or just stop after one level
function drawSubTriangles(t, recursive) {
    //End condition, bounded by maximum recursion depth
    if(depth == maxDepth && recursive==true) {
        //Push triangle to depth collection, to track in case zooming in and redrawing
        triangles[maxDepth-depth].push(t);
        return;
    }

    depth = depth + 1;

    //Sub triangle lengths are half of parent triangle
    subLength = length/depth;

    var midPoint1 = getCenter(t.p1, t.p2);
    var midPoint2 = getCenter(t.p2, t.p3);
    var midPoint3 = getCenter(t.p3, t.p1);

    midTriangle = new Triangle(midPoint1, midPoint2, midPoint3);

    sketchTriangle(midTriangle)

    //Recursive call to continue drawing children triangles until max depth
    if(recursive == true) {
        drawSubTriangles(new Triangle(t.p1, midPoint1, midPoint3), true);
        drawSubTriangles(new Triangle(midPoint3, midPoint2, t.p3), true);
        drawSubTriangles(new Triangle(midPoint1, t.p2, midPoint2), true);
    }
    depth = depth -1;
}



function sketchTriangle(t) {
    drawLine(t.p1, t.p2);
    drawLine(t.p2, t.p3);
    drawLine(t.p3, t.p1);
}

function create2DArray(rows) {
    var arr = [];

    for (var i=0;i<rows;i++) {
        arr[i] = [];
    }

    return arr;
}

function getCenter(p1, p2) {
    return new Point((p1.x + p2.x)/2, (p1.y + p2.y)/2);
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}

function Triangle(p1, p2, p3) {
    this.p1 = p1;
    this.p2 = p2;
    this.p3 = p3;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ariutta.github.io/svg-pan-zoom/dist/svg-pan-zoom.js"></script>
<div id="drawing"></div>


Примечание: я не понимаю, почему svg-pan-zoom не просто изменяет SVG viewBox приписывать. Тогда не нужно было бы вообще изменять структуру документа.

Другие вопросы по тегам