SVG에서 변환 원점을 설정하는 방법


104

자바 스크립트를 사용하여 SVG 문서에서 특정 요소의 크기를 조정하고 회전해야합니다. 문제는 기본적으로 항상 (0, 0)왼쪽 상단 의 원점 주위에 변환을 적용한다는 것 입니다.

이 변형 기준점을 어떻게 다시 정의 할 수 있습니까?

transform-origin속성을 사용해 보았지만 아무런 영향을 미치지 않습니다.

이것이 내가 한 방법입니다.

svg.getDocumentById('someId').setAttribute('transform-origin', '75 240');

Firefox에서 속성이 올바르게 설정되었음을 알 수 있지만 중심점을 지정한 지점으로 설정하지 않는 것 같습니다. 내가 좋아하는 일을 시도 center bottom50% 100%함께 괄호없이. 지금까지 아무것도 작동하지 않았습니다.

누구든지 도울 수 있습니까?


FWIW, Firefox 19 베타 3에서 수정되었지만 Firefox 22에서는 여전히 문제가 있습니다. Mozilla bugzilla 목록 : bugzilla.mozilla.org/show_bug.cgi?id=828286
Toph

답변:


147

회전하려면를 사용하십시오 transform="rotate(deg, cx, cy)". 여기서 deg는 회전하려는 각도이고 (cx, cy)는 회전 중심을 정의합니다.

크기 조정 / 크기 조정의 경우 (-cx, -cy)로 변환 한 다음 크기를 조정 한 다음 다시 (cx, cy)로 변환해야합니다. 행렬 변환 으로이 작업을 수행 할 수 있습니다 .

transform="matrix(sx, 0, 0, sy, cx-sx*cx, cy-sy*cy)"

여기서 sx는 x 축의 배율 인수이고 y 축의 sy입니다.


정말 고맙습니다. 회전은 완벽하게 작동한다고 생각하지만 크기 조정 / 크기 조정은 항상 임의의 양만큼 떨어져 나갑니다. 나는 매트릭스를 사용하여 "translate (cx sx, cy sy) scale (sx, sy)" 와 같이 따로 해보았습니다 . 같은 결과.
CTheDark 2011

6
transform = "matrix (sx, 0, 0, sy, cx-sx cx, cy-sy cy)"가 아닐까요? 차이에 의해서만 번역하고 싶기 때문입니다. 이 논리가 맞다고 생각하지만 여전히 제 위치를
잃어 버립니다

이제 작동합니다! 잘못된 cx 및 cy 값을 사용하고있었습니다! 감사합니다!
CTheDark

1
@JayStevens 예, 행렬 변환은 모든 시스템에서 작동합니다. 단지 수학 일뿐입니다. 유일한 차이점은 표기법 일 수 있습니다. 내가 알 수있는 한, CSS 행렬 변환은 SVG와 동일한 표기법을 사용하므로 해당 순서의 동일한 6 개 숫자가 작동합니다.
Peter Collingridge 2014-08-01

1
명확하게하기 위해 cx와 cy는 크기를 조정하는 상자 중심 의 오프셋이어야합니다 . CSS 상자 모델에서 생각하는 것처럼 이로 인해 잠시 동안 나를 넘어 뜨 렸습니다. @forresto는 아래의 답변에서 이것을 암시합니다.
제이슨 워스

22

고정 값 ( "center"또는 "50 %"아님)을 사용할 수있는 경우 대신 CSS를 사용할 수 있습니다.

-moz-transform-origin: 25px 25px;
-ms-transform-origin:  25px 25px;
-o-transform-origin: 25px 25px;
-webkit-transform-origin:  25px 25px;
transform-origin: 25px 25px;

Firefox와 같은 일부 브라우저는 상대 값을 올바르게 처리하지 않습니다.


1
와. 내가 할 수 있다면 +10. 이것은 내 하루를 구했습니다! 감사.
Cullub

이것을 수행하는 방법과 JavaScript에서 이것을 수행하는 방법은 무엇입니까?
Andrew S

처럼 element.setAttribute('transform-origin', '25px 25px')?
nikk wong

13

나와 같고 transform-origin으로 이동 한 다음 확대 / 축소하려면 조금 더 필요합니다.

// <g id="view"></g>
var view = document.getElementById("view");

var state = {
  x: 0,
  y: 0,
  scale: 1
};

// Origin of transform, set to mouse position or pinch center
var oX = window.innerWidth/2;
var oY = window.innerHeight/2;

var changeScale = function (scale) {
  // Limit the scale here if you want
  // Zoom and pan transform-origin equivalent
  var scaleD = scale / state.scale;
  var currentX = state.x;
  var currentY = state.y;
  // The magic
  var x = scaleD * (currentX - oX) + oX;
  var y = scaleD * (currentY - oY) + oY;

  state.scale = scale;
  state.x = x;
  state.y = y;

  var transform = "matrix("+scale+",0,0,"+scale+","+x+","+y+")";
  //var transform = "translate("+x+","+y+") scale("+scale+")"; //same
  view.setAttributeNS(null, "transform", transform);
};

여기에서 작동합니다 : http://forresto.github.io/dataflow-prototyping/react/


귀하의 GitHub의 링크 404
NuclearPeon

안녕하세요 @NuclearPeon, 이것은 굉장하지만 내 코드에서 구현할 수없는 것 같습니다. 적용하고 싶은 SVG 요소는 이미 "mainGrid"라는 변수입니다. 나는 효과없이 "view"의 인스턴스를 "mainGrid"로 바꾸려고했다. 내가 무엇을 놓치고 있습니까? 감사!
sakeferret 19

@sakeferret에서 확인해야 할 가장 분명한 사항 idgetElementById및 문서 id="..."속성 의 일치 여부입니다 . 코드를 보지 않고는 확실히 알기 어렵습니다. SO 질문으로 게시하고 싶지 않다면 작동 할 때까지 속성 이름을 사용하여 가장 간단한 예제를 만들고 / 문제를 찾은 다음 나머지를 다시 추가 할 수 있습니다.
NuclearPeon

12

matrix변환 을 사용하지 않고 크기를 조정하려면 :

transform="translate(cx, cy) scale(sx sy) translate(-cx, -cy)"

그리고 여기 CSS에 있습니다.

transform: translate(cxpx, cypx) scale(sx, sy) translate(-cxpx, -cypx)

1

우리 모두 여기서 트릭을 놓친 것 같습니다. transform-box: fill-box

를 사용 transform-box: fill-box하면 SVG 내의 요소가 일반 HTML 요소처럼 작동합니다. 그런 다음 transform-origin: center평소처럼 신청할 수 있습니다 (또는 다른 것).

맞습니다. transform-box: fill-box복잡한 매트릭스는 필요 없습니다.


매우 유용한 솔루션, 이것은 더 높게 upvoted 될 것입니다. 이것이 바로 제가 필요로하는 것입니다. 감사합니다! svg 및 html 요소는 변환 및 전환시 미묘한 차이가 있습니다. 나는이 답변을 찾을 때까지 몇 시간 동안 애니메이션 버그로 당황했습니다 ... transform-box: fill-box;당신 과 함께 transform-origin정상적인 방식으로 / 당신이 기대하는 것처럼 svg 요소를 존중할 수 있습니다 !
zfogg

-1

비슷한 문제가있었습니다. 하지만 D3 를 사용하여 요소의 위치를 ​​지정 하고 CSS 에서 변환전환 을 처리하기를 원했습니다 . 이것은 Chrome 65에서 작업 한 원래 코드입니다.

//...
this.layerGroups.selectAll('.dot')
  .data(data)
  .enter()
  .append('circle')
  .attr('transform-origin', (d,i)=> `${valueScale(d.value) * Math.sin( sliceSize * i)} 
                                     ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)}`)
//... etc (set the cx, cy and r below) ...

이 날이 설정할 수 cx, cytransform-origin동일한 데이터를 이용하여 자바 스크립트 값.

그러나 이것은 Firefox에서 작동하지 않았습니다! 내가해야 할 일은 위와 동일한 위치 지정 공식을 사용하여 태그를 감싸는 것 circle입니다 . 그런 다음 태그 에 를 추가 하고 및 값을 . 거기에서 예상대로 중앙에서 확장됩니다. 최종 코드는 다음과 같습니다.gtranslatecirclegcxcy0transform: scale(2)

this.layerGroups.selectAll('.dot')
  .data(data)
  .enter()
  .append('g')
  .attrs({
    class: d => `dot ${d.metric}`,
    transform: (d,i) => `translate(${valueScale(d.value) * Math.sin( sliceSize * i)} ${valueScale(d.value) * Math.cos( sliceSize * i + Math.PI)})`
  })
  .append('circle')
  .attrs({
    r: this.opts.dotRadius,
    cx: 0,
    cy: 0,
  })

이 변경을 한 후, 나는 대상으로 내 CSS 변경 circle대신의 .dot을 추가를 transform: scale(2). 나는 사용할 필요조차 없었습니다 transform-origin.

노트:

  1. d3-selection-multi두 번째 예에서 사용 하고 있습니다. 이를 통해 모든 속성에 대해 .attrs반복 하는 대신 객체를 전달할 수 있습니다 .attr.

  2. 문자열 템플릿 리터럴을 사용하는 경우 첫 번째 예에 설명 된대로 줄 바꿈에 유의하십시오. 이것은 출력에 개행을 포함하고 코드를 손상시킬 수 있습니다.


2
아마도 transform-box : fill-box; Firefox는 원하는 방식으로 작동했을 것입니다.
Robert Longson

그것을 시도했습니다. 작동하지 않는 것 같습니다. 그것은 내가 변경 한 후 작업을 svg:transform-origin.enabled파이어 폭스의에서 현 about:config페이지를. 하지만 ... 그것은 적절한 해결책처럼 보이지 않았습니다. 또한 transform-origin: 50% 50%과 (와) 사이의 불일치를 발견했습니다 transform-origin: center center.
Jamie S

svg.transform-origin.enabled pref는 여러 버전 전에 제거되었습니다. 아주 오래된 버전을 사용하지 않는 한 50 %와 center 사이에 차이가 없어야합니다. Firefox 59 이상에서 차이가 있으면 버그질라 버그를 자유롭게 제기하십시오.
Robert Longson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.