Замена d3.transform в D3 v4

В D3.js v4 метод d3.transform удален, без каких-либо намеков о том, как его заменить. Кто-нибудь знает, как заменить следующую инструкцию D3.js v3?

d3.transform(String).translate;

Ответы

Ответ 1

Изменить 2016-10-07:. Для более общего подхода см. ниже.


В соответствии с изменением он исчез. Однако существует функция transform/decompose.js, которая выполняет вычисления для внутреннего использования. К сожалению, он не предназначен для внешнего использования.

Тем не менее, это легко сделать даже без использования D3:

function getTranslation(transform) {
  // Create a dummy g for calculation purposes only. This will never
  // be appended to the DOM and will be discarded once this function 
  // returns.
  var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
  
  // Set the transform attribute to the provided string value.
  g.setAttributeNS(null, "transform", transform);
  
  // consolidate the SVGTransformList containing all transformations
  // to a single SVGTransform of type SVG_TRANSFORM_MATRIX and get
  // its SVGMatrix. 
  var matrix = g.transform.baseVal.consolidate().matrix;
  
  // As per definition values e and f are the ones for the translation.
  return [matrix.e, matrix.f];
}

console.log(getTranslation("translate(20,30)"))  // simple case: should return [20,30]
console.log(getTranslation("rotate(45) skewX(20) translate(20,30) translate(-5,40)"))

Ответ 2

Если вы выберете d3 v4 через npm, вы можете напрямую импортировать файл src/transform/parse и вызвать parseSvg:

// using es2015 modules syntax
import { parseSvg } from "d3-interpolate/src/transform/parse";

parseSvg("translate(20, 20)");

Ответ 3

В элементах, на которых есть слушатель d3.js zoom - обычно элемент <g>, прикрепленный к элементу svg, - вы можете использовать этот вызов для получения атрибутов преобразования вне функции масштабирования:

var self = this;
var t = d3.zoomTransform(self.svg.node()); 

// t = {k: 1, x: 0, y: 0} or your current transformation values

Это возвращает те же значения, что и при вызове d3.event.transform внутри самой функции события масштабирования.

Вызов d3.event.transform вне функции события масштабирования приведет к ошибке: Uncaught TypeError: Cannot read property 'transform' of null

Мне нужно использовать d3.zoomTransform, чтобы разрешить панорамирование и масштабирование с помощью кнопок вне графика.

Ответ 4

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

Код выше @altocumulus довольно тщательный и работает как шарм. Однако это не совсем соответствовало моим потребностям, так как я делал расчеты вручную и нуждался в том, чтобы изменить некоторые свойства преобразования настолько безболезненно, насколько это возможно.

Это может быть не решение для всех, но это было идеально для меня.

function _getTokenizedTransformAttributeValue(transformStr) {
    var cleanedUpTransformAttrArr = transformStr.split(')', ).slice(0,-1);

    return cleanedUpTransformAttrArr.reduce(function(retObj, item) { 
        var transformPair = item.split('(');

        retObj[transformPair[0]] = transformPair[1].split(',');

        return retObj;
    }, {});
}

 

function _getStringFromTokenizedTransformAttributeObj(transformAttributeObj) {
    return _.keys(transformAttributeObj).reduce(function(finalStr, key) {
        // wrap the transformAttributeObj[key] in array brackets to ensure we have an array
        // join will flatten the array first and then do the join so [[x,y]].join(',') -> "x,y"
        return finalStr += key + "(" + [transformAttributeObj[key]].join(',') + ")"; 
     }, '');
}

Самое замечательное в первой функции - это то, что я могу вручную изменить конкретное свойство (например, вращение) и не беспокоиться о том, как он влияет на перевод или что-то еще (при повороте вокруг точки), тогда как когда я полагаюсь по встроенным или даже d3.transform методам они объединяют все свойства в одно значение.

Почему это круто?

Представьте себе некоторый HTML

<g class="tick-label tick-label--is-rotated" transform="translate(542.8228777985075,0) rotate(60, 50.324859619140625, 011.402383210764288)" style="visibility: inherit;"></g>


Используя d3.transfrom, я получаю:

В объектной форме

jr {rotate: 59.99999999999999, translate: [577.8600589984691, -37.88141544673796], scale: [1, 1], skew: 0, toString: function} 


В строковой форме

"translate(577.8600589984691,-37.88141544673796)rotate(59.99999999999999)skewX(0)scale(1,1)"


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


Использование моей функции _getTokenizedTransformAttributeValue

В объектной форме

{translate: ["542.8228777985075", "0"],  rotate: ["60", " 50.324859619140625", " 011.402383210764288"]}


В строковой форме с использованием функции _getStringFromTokenizedTransformAttributeObj

"translate(542.8228777985075,0)rotate(60, 50.324859619140625, 011.402383210764288)"


Это прекрасно, потому что теперь, когда вы удаляете вращение, ваш элемент может вернуться туда, где он был

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

Ответ 5

Я нашел способ добиться чего-то подобного, используя это:

d3.select(this).node().getBBox();

это даст вам доступ к позиции x/y и ширине/высоте Здесь вы можете увидеть пример: https://bl.ocks.org/mbostock/1160929

Ответ 6

Я нашел немного более простое решение, чем это.

selection.node().transform.baseVal[0].matrix

В этой матрице у вас есть корни e и f, которые эквивалентны x, y. (e === x, f === y). Нет необходимости реализовывать для вас свои собственные функции.

baseVal - это список преобразований элемента. Вы не можете использовать это для объекта без преобразования превиума! (список будет пустым). Если вы сделали много преобразований для объекта, последняя позиция будет находиться под последним элементом списка baseVal.