Как установить происхождение трансформации в SVG

Мне нужно resize и повернуть некоторые элементы в документе SVG с помощью javascript. Проблема заключается в том, что по умолчанию она всегда применяет преобразование вокруг начала координат в (0, 0) – вверху слева.

Как я могу переопределить эту точку привязки преобразования?

Я попытался использовать атрибут transform-origin , но он ничего не влияет.

Вот как я это сделал:

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

Кажется, он не указывает ключевую точку на указанную мной точку, хотя я могу видеть в Firefox, что атрибут правильно установлен. Я пробовал такие вещи, как center bottom и 50% 100% с круглыми скобками и без них. До сих пор ничего не работало.

Может ли кто-нибудь помочь?

Чтобы повернуть использование 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, sy – по оси y.

Если вы можете использовать фиксированное значение (не «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) неправильно обрабатывают относительные значения.

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

 //  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/

Для масштабирования без использования matrix преобразования:

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

И вот это в CSS:

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

У меня была аналогичная проблема. Но я использовал 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 в javascript, используя те же данные.

НО это не работает в Firefox! То, что мне нужно было сделать, это обернуть circle в теге g и translate его, используя ту же формулу позиционирования сверху. Затем я добавил circle в тег g и установил его значения cx и cy равными 0 . Оттуда transform: 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 втором примере я использую d3-selection-multi . Это позволяет мне передать объект в .attrs вместо повторения .attr для каждого атрибута.

  2. При использовании строкового литерала шаблона следует учитывать разрывы строк, как показано в первом примере. Это будет включать новую строку в выходе и может нарушить ваш код.

Давайте будем гением компьютера.