首页 > 解决方案 > 无法将屏幕 x,y 坐标转换为 svg 坐标

问题描述

我正在尝试将从 click 事件中获取的位置转换为应该附加到我想要附加到我的<svg>. 每次单击时,我都想在单击的位置添加一个元素,例如圆形。我已经读过point.matrixTransform(svgRoot.getScreenCTM().inverse());应该做的伎俩并将屏幕坐标转换为SVG坐标,但在我的情况下它似乎不起作用(坐标根本不翻译)。仅当我将viewBox属性添加到我的<svg>. 我不知道我在这里做错了什么。也许这不适用于我的情况,我需要手动进行转换?

例子:

const drawingArea = document.querySelector('#drawing-area');
drawingArea.addEventListener('click', (e) => {
  const { left, top } = drawingArea.getBoundingClientRect();
  drawCircle({
    x: e.clientX - left,
    y: e.clientY - top});
});

const drawCircle = ({ x, y }, r = 10) => {
  const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
  circle.setAttribute('cx', x.toString());
  circle.setAttribute('cy', y.toString());
  circle.setAttribute('r', r.toString());
  drawingArea.appendChild(circle);
}

const translateToSVGCoordinates = (x, y) => {
  const point = drawingArea.createSVGPoint();
  point.x = x;
  point.y = y;
  point.matrixTransform(drawingArea.getScreenCTM().inverse());
  return { x: point.x, y: point.y };
}      
body, html {
    width: 100%;
    height: 100%;
    margin: 0;
}
<svg id="drawing-area" width="100%" height="100%" viewBox="0 0 1920 1080" preserveAspectRatio="xMinYMin meet"></svg>

如果我不够清楚我期待什么结果,只需从元素中删除viewBox属性<svg>

标签: javascripthtmlsvg

解决方案


您使用 SVG 代码和 Web 组件代码使其过于复杂......

尝试这个:

<svg-draw-board></svg-draw-board>
<style>
  svg-draw-board {
    width      : 100vw;
    height     : 180px;
    display    : inline-block;
    background : pink;
    cursor     : pointer;
  }
</style>
<script>
customElements.define('svg-draw-board', class extends HTMLElement {
  constructor() {
    super()
       .attachShadow({mode:'open'})
       .innerHTML = `<svg width="100%" height="100%" viewBox="0 0 800 800"></svg>`;
    this.svg = this.shadowRoot.querySelector('svg');
    this.svg.onclick = (evt) => { // convert clientXY to SVG XY
      let CTM = this.svg.getScreenCTM();
      let x = (evt.clientX - CTM.e) / CTM.a;
      let y = (evt.clientY - CTM.f) / CTM.d;
      this.drawCircle( x, y , evt.ctrlKey ? 50 : 30 );
    };
  }
  drawCircle(cx, cy, r, fill = 'red') {
    this.svg.append( this.createSVGElement('circle', { cx, cy, r, fill }) );
  }
  createSVGElement( tag, attrs={} ) {
    const el = document.createElementNS('http://www.w3.org/2000/svg',tag);
    Object.entries(attrs).map(([name, val]) => el.setAttribute(name, val));
    return el;
  }
});
</script>


推荐阅读