установить фокус на любой узел в большом документе SVG - PullRequest
0 голосов
/ 20 января 2019

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

Часть моих требований - иметь возможность иметь меню, в котором вы можете выбрать один из узлов, которые являются шестиугольниками вПример ниже, а затем фокус будет на этом узле или шестиугольнике.

Как я могу расположить документ на любом узле.

Например, если я нажму кнопку в примере, какМогу ли я сфокусироваться на шестиугольнике, который является наиболее правым?

Я думаю, что мог бы использовать viewBox, но я хотел бы получить несколько советов о том, как этого добиться.

Я мог бы использоватьminX и minY, которые являются первыми 2 аргументами viewBox.

Но как бы мне установить эти значения?

Получу ли я x и y изgetBBox значения узла?

const SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_XLINK = "http://www.w3.org/1999/xlink";

let A = -1200;
let B = 1200;

let hexArray = []

function drawHexagon(r){  
  let points = "";
   for( let i = 1; i <= 6; i++ ){
        let a = i * ( Math.PI / 3 );
        let x = (r * Math.cos( a - Math.PI/2 )).toFixed(3);
        let y = (r * Math.sin( a  - Math.PI/2)).toFixed(3);
        points += `${x},${y} `;
      }
  return points;
}

function useHex(theParent,pos){
   let use = document.createElementNS(SVG_NS, 'use');
   use.setAttributeNS(SVG_XLINK, 'xlink:href', '#theHex');
   use.setAttributeNS(null,"x",pos.x);
   use.setAttributeNS(null,"y",pos.y);
   //use.setAttribute("title",'x value:'+pos.x);
   theParent.appendChild(use);
   hexArray.push(use);
  
   drawText('x value:'+pos.x,pos)
}

function drawText(val,pos){
  let txt = document.createElementNS(SVG_NS, 'text');
  txt.setAttributeNS(null,"x",pos.x);
  txt.setAttributeNS(null,"y",pos.y);
  txt.textContent = val;
  txt.setAttributeNS(null,"transform",`translate(0,30) rotate(-75  ${pos.x},${pos.y})`);
  textParent.appendChild(txt);
}

function connector(parent,p){
  let path = document.createElementNS(SVG_NS, 'path');
  let d =`M${p.x},${p.y}C${p.x},125 0,125 0,0`;
  path.setAttributeNS(null,"d",d);
  parent.appendChild(path);
}

for(let x = A; x <= B; x+=50){
  let pos = {x:x,y:250}
  useHex(useParent,pos);
  connector(connectors,pos);
}



document.querySelector('button').addEventListener("click",()=>{
  alert('how do I focus on a node, including those that are off screen');
});
svg {
  border: 1px solid;
}
use {
  fill: white;
  stroke: #000;
}

#itr {
  width: 500px;
  display: block;
  margin: 2em auto;
}

#connectors path {
  fill: none;
  stroke: black;
}

#tooltip {
  position: absolute;
}

text {
  dominant-baseline: middle;
  text-anchor: end;
}
<button type="button">select node</button>

<svg id="svg" viewBox="-600 -50 1200 550" style="--display:block;">
<defs><polygon  id="theHex"  points="21.651,-12.500 21.651,12.500 0.000,25.000 -21.651,12.500 -21.651,-12.500 -0.000,-25.000 "  ></polygon>
</defs> 
<g id="connectors">
  
</g>
<g id="useParent">
<use xlink:href="#theHex" y="0"  />
</g>
<g id="textParent">
  
</g>
</svg>

Ответы [ 2 ]

0 голосов
/ 20 января 2019

Если я правильно понимаю, вы хотите увеличить выбранный узел. Как вы писали, вы можете сделать это, используя viewBox. Я добавил следующий фрагмент в ваш код:

var svg = document.getElementById('svg')
document.getElementById('useParent').addEventListener('click', evt => {
  if(evt.target.nodeName === 'use') {
      focusNode(evt.target);
  }
});
function focusNode(node) {
    var bbox = node.getBBox()
    svg.setAttribute('viewBox', `${bbox.x - 250} ${bbox.y - 30} 600 275`)
    node.setAttribute('style', 'fill:red;');
    //TODO: need to clear the previous selection
}
document.querySelector('button').addEventListener("click",()=>{
  focusNode(hexArray[0]);
});

Он делится пополам width и height на viewBox: 600 275 против оригинала 1200 550. В основном это 2-кратный зум. И это меняет min-x и min-y viewBox, чтобы сделать шестиугольник примерно в центре SVG.

const SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_XLINK = "http://www.w3.org/1999/xlink";

let A = -1200;
let B = 1200;

let hexArray = []

function drawHexagon(r){  
  let points = "";
   for( let i = 1; i <= 6; i++ ){
        let a = i * ( Math.PI / 3 );
        let x = (r * Math.cos( a - Math.PI/2 )).toFixed(3);
        let y = (r * Math.sin( a  - Math.PI/2)).toFixed(3);
        points += `${x},${y} `;
      }
  return points;
}

function useHex(theParent,pos){
   let use = document.createElementNS(SVG_NS, 'use');
   use.setAttributeNS(SVG_XLINK, 'xlink:href', '#theHex');
   use.setAttributeNS(null,"x",pos.x);
   use.setAttributeNS(null,"y",pos.y);
   //use.setAttribute("title",'x value:'+pos.x);
   theParent.appendChild(use);
   hexArray.push(use);
  
   drawText('x value:'+pos.x,pos)
}

function drawText(val,pos){
  let txt = document.createElementNS(SVG_NS, 'text');
  txt.setAttributeNS(null,"x",pos.x);
  txt.setAttributeNS(null,"y",pos.y);
  txt.textContent = val;
  txt.setAttributeNS(null,"transform",`translate(0,30) rotate(-75  ${pos.x},${pos.y})`);
  textParent.appendChild(txt);
}

function connector(parent,p){
  let path = document.createElementNS(SVG_NS, 'path');
  let d =`M${p.x},${p.y}C${p.x},125 0,125 0,0`;
  path.setAttributeNS(null,"d",d);
  parent.appendChild(path);
}

for(let x = A; x <= B; x+=50){
  let pos = {x:x,y:250}
  useHex(useParent,pos);
  connector(connectors,pos);
}

var svg = document.getElementById('svg')
document.getElementById('useParent').addEventListener('click', evt => {
  if(evt.target.nodeName === 'use') {
    focusNode(evt.target)
  }
});

function focusNode(node) {
  var bbox = node.getBBox()
    svg.setAttribute('viewBox', `${bbox.x - 250} ${bbox.y - 30} 600 275`)
    node.setAttribute('style', 'fill:red;')
}

document.querySelector('button').addEventListener("click",()=>{
  focusNode(hexArray[0]);
});
svg {
  border: 1px solid;
}
use {
  fill: white;
  stroke: #000;
}

#itr {
  width: 500px;
  display: block;
  margin: 2em auto;
}

#connectors path {
  fill: none;
  stroke: black;
}

#tooltip {
  position: absolute;
}

text {
  dominant-baseline: middle;
  text-anchor: end;
}
<button type="button">select 1st node</button>

<svg id="svg" viewBox="-600 -50 1200 550" style="--display:block;">
<defs><polygon  id="theHex"  points="21.651,-12.500 21.651,12.500 0.000,25.000 -21.651,12.500 -21.651,-12.500 -0.000,-25.000 "  ></polygon>
</defs> 
<g id="connectors">
  
</g>
<g id="useParent">
<use xlink:href="#theHex" y="0"  />
</g>
<g id="textParent">
  
</g>
</svg>
0 голосов
/ 20 января 2019

Я добавил tabindex атрибуты к элементам <use>. Это помогает сделать эти шестиугольники фокусируемыми.

Когда вы нажимаете кнопку, вы фокусируете элемент, для которого tabindex (в данном случае) 20. Затем, когда вы нажимаете клавишу Tab на клавиатуре, вы перемещаете фокус на следующий шестиугольник.

Я установил атрибут viewBox вашего svg в вазе на значение атрибута x целевого элемента.

const SVG_NS = 'http://www.w3.org/2000/svg';
const SVG_XLINK = "http://www.w3.org/1999/xlink";

let A = -1200;
let B = 1200;

let hexArray = []

function drawHexagon(r){  
  let points = "";
   for( let i = 1; i <= 6; i++ ){
        let a = i * ( Math.PI / 3 );
        let x = (r * Math.cos( a - Math.PI/2 )).toFixed(3);
        let y = (r * Math.sin( a  - Math.PI/2)).toFixed(3);
        points += `${x},${y} `;
      }
  return points;
}

function useHex(theParent,pos){
   let use = document.createElementNS(SVG_NS, 'use');
   use.setAttributeNS(SVG_XLINK, 'xlink:href', '#theHex');
   use.setAttributeNS(null,"x",pos.x);
   use.setAttributeNS(null,"y",pos.y);
   use.setAttributeNS(null,"tabindex",pos.i);
   
   theParent.appendChild(use);
   hexArray.push(use);
  
   drawText('x value:'+pos.x,pos)
}

function drawText(val,pos){
  let txt = document.createElementNS(SVG_NS, 'text');
  txt.setAttributeNS(null,"x",pos.x);
  txt.setAttributeNS(null,"y",pos.y);
  txt.textContent = val;
  txt.setAttributeNS(null,"transform",`translate(0,30) rotate(-75  ${pos.x},${pos.y})`);
  textParent.appendChild(txt);
}

function connector(parent,p){
  let path = document.createElementNS(SVG_NS, 'path');
  let d =`M${p.x},${p.y}C${p.x},125 0,125 0,0`;
  path.setAttributeNS(null,"d",d);
  parent.appendChild(path);
}

for(let x = A,i=0; x <= B; x+=50,i++){
  let pos = {x:x,y:250,i:i}
  useHex(useParent,pos);
  connector(connectors,pos);
}

let theButton = document.querySelector('[type=button]')

theButton.addEventListener("click",()=>{
  let index = theButton.value;
  let active = document.querySelector(`[tabindex = '${index}']`)
  active.focus()
  //alert('how do I focus on a node, including those that are off screen');
});


// event listener for keyup
function checkTabPress(e) {
    if (e.keyCode == 9) {
        let activeElement = document.activeElement;
        let posX = activeElement.getAttribute("x"); 
        svg.setAttributeNS(null, "viewBox", `${posX - 600} -50 1200 550`); 
    }
}


document.querySelector('body').addEventListener('keyup', checkTabPress);
svg {
  border: 1px solid;
}
use {
  fill: white;
  stroke: #000;
}


#connectors path {
  fill: none;
  stroke: black;
}

#tooltip {
  position: absolute;
}

text {
  dominant-baseline: middle;
  text-anchor: end;
}

use:focus{fill:red}
<button type="button" value="20">select node</button>

<svg id="svg" viewBox="-600 -50 1200 550" style="--display:block;">
<defs><polygon  id="theHex"  points="21.651,-12.500 21.651,12.500 0.000,25.000 -21.651,12.500 -21.651,-12.500 -0.000,-25.000 "  ></polygon>
</defs> 
<g id="connectors">
  
</g>
<g id="useParent">
<use xlink:href="#theHex" y="0"  />
</g>
<g id="textParent">
  
</g>
</svg>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...