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


104

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

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

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

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

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

Firefox에서 속성이 올바르게 설정되었음을 알 수 있지만 중심점을 지정한 지점으로 설정하지 않는 것 같습니다. 내가 좋아하는 일을 시도 center bottom와 50% 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에서 확인해야 할 가장 분명한 사항 id은 getElementById및 문서 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, cy및 transform-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.