Skip to content

Commit

Permalink
Merge pull request #328 from magjac/fix-rotate
Browse files Browse the repository at this point in the history
Fix rotate=90 graph attribute does not set the rotation
  • Loading branch information
magjac authored Oct 14, 2024
2 parents b15c28a + 952d2db commit 355158d
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 19 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
* rotate=90 graph attribute does not set the rotation #251

## [5.6.0] – 2024-08-18

### Changed
Expand All @@ -22,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Upgrade @hpcc-js/wasm to 2.16.2 (Graphviz 11.0.0)

### Fixed
* Cluster's box shadows nodes inside it after animated transition
* Cluster's box shadows nodes inside it after animated transition #308

## [5.3.0] – 2024-02-11

Expand Down
6 changes: 3 additions & 3 deletions examples/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
a -> c
}`,
`digraph {
node [style="filled"]
node [style="filled"]
a [fillcolor="#d62728" shape="box"]
b [fillcolor="#1f77b4" shape="parallelogram"]
c [fillcolor="#2ca02c" shape="pentagon"]
Expand All @@ -70,7 +70,7 @@
b -> c
}`,
`digraph {
node [style="filled"]
node [style="filled"]
a [fillcolor="#d62728" shape="triangle"]
b [fillcolor="#1f77b4" shape="diamond"]
c [fillcolor="#2ca02c" shape="trapezium"]
Expand All @@ -79,7 +79,7 @@
b -> c
}`,
`digraph {
node [style="filled"]
node [style="filled"]
a [fillcolor="#d62728" shape="box"]
b [fillcolor="#1f77b4" shape="parallelogram"]
c [fillcolor="#2ca02c" shape="pentagon"]
Expand Down
14 changes: 12 additions & 2 deletions src/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,18 @@ export function extractElementData(element) {
var transform = element.node().transform;
if (transform && transform.baseVal.numberOfItems != 0) {
var matrix = transform.baseVal.consolidate().matrix;
datum.translation = {x: matrix.e, y: matrix.f};
datum.scale = matrix.a;
if (matrix.b == 0) {
// drawing orientation is portrait
datum.translation = { x: matrix.e, y: matrix.f };
datum.scale = matrix.a;
datum.rotation = 0;
}
else {
// drawing orientation is landscape
datum.translation = { x: matrix.e, y: matrix.f };
datum.scale = matrix.c;
datum.rotation = -90;
}
}
if (tag == 'ellipse') {
datum.center = {
Expand Down
1 change: 1 addition & 0 deletions src/graphviz.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export function Graphviz(selection, options) {
this._images = [];
this._translation = undefined;
this._scale = undefined;
this._rotation = undefined;
this._eventTypes = [
'initEnd',
'start',
Expand Down
8 changes: 6 additions & 2 deletions src/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,12 @@ function _render(callback) {
elementTransition
.tween("attr.transform", function() {
var node = this;
return function(t) {
node.setAttribute("transform", interpolateTransformSvg(zoomTransform(graphvizInstance._zoomSelection.node()).toString(), getTranslatedZoomTransform.call(graphvizInstance, element).toString())(t));
return function (t) {
const rotateStr = ` rotate(${data.rotation})`;
const fromTransform = zoomTransform(graphvizInstance._zoomSelection.node()).toString() + rotateStr;
const toTransform = getTranslatedZoomTransform.call(graphvizInstance, element).toString() + rotateStr;
const interpolationFunction = interpolateTransformSvg(fromTransform, toTransform);
node.setAttribute("transform", interpolationFunction(t));
};
});
}
Expand Down
13 changes: 12 additions & 1 deletion src/zoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@ export function createZoomBehavior() {
var graphvizInstance = this;
function zoomed(event) {
var g = d3.select(svg.node().querySelector("g"));
g.attr('transform', event.transform);
var transform = g.node().transform;
var matrix = transform.baseVal.consolidate().matrix;
if (matrix.b == 0) {
// drawing orientation is portrait
g.attr('transform', event.transform);
}
else {
// drawing orientation is landscape
const t = event.transform;
const transformStr = `rotate(-90) translate(${-t.y} ${t.x}) scale(${t.k})`;
g.attr('transform', transformStr);
}
graphvizInstance._dispatch.call('zoom', graphvizInstance);
}

Expand Down
1 change: 1 addition & 0 deletions test/dot-data-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ var basic_data = {
"y": 112
},
"scale": 1,
"rotation": 0,
"parent": "[Circular ~]",
"children": [
{
Expand Down
14 changes: 14 additions & 0 deletions test/it.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,17 @@ export default function it_wrapper(decription, run) {
});
});
}

export function it_xfail(decription, run) {
it(decription + " XFAIL", async function () {
await new Promise(async (resolve, reject) => {
try {
await run.call(this);
}
catch (e) {
resolve();
}
reject(Error("The test unexpectedly passed (XPASS)"));
});
});
}
24 changes: 14 additions & 10 deletions test/jsdom.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,29 +93,33 @@ export default function jsdomit(html, options) {
if (!('transform' in window.SVGElement.prototype)) {
Object.defineProperty(window.SVGElement.prototype, 'transform', {
get: function() {
if (this.getAttribute('transform')) {
var translate = this.getAttribute('transform').replace(/.*translate\((-*[\d.]+[ ,]+-*[\d.]+)\).*/, function(match, xy) {
const transform = this.getAttribute('transform');
if (transform) {
var translate = transform.replace(/.*translate\((-*[\d.]+[ ,]+-*[\d.]+)\).*/, function(match, xy) {
return xy;
}).split(/[ ,]+/).map(function(v) {
return +v;
});
var scale = this.getAttribute('transform').replace(/.*.*scale\((-*[\d.]+[ ,]*-*[\d.]*)\).*/, function(match, scale) {
var scale = transform.includes('scale') ? transform.replace(/.*scale\((-*[\d.]+[ ,]*-*[\d.]*)\).*/, function(match, scale) {
return scale;
}).split(/[ ,]+/).map(function(v) {
return +v;
});
}) : 1;
var rotate = transform.includes('rotate') ? transform.replace(/.*rotate\((-*[\d.]+)\).*/, function (match, rotate) {
return rotate;
}) : 0;
return {
baseVal: {
numberOfItems: 1,
consolidate: function() {
return {
matrix: {
'a': scale[0],
'b': 0,
'c': 0,
'd': scale[1] || scale[0],
'e': translate[0],
'f': translate[1],
'a': rotate == 0 ? scale[0] : 0,
'b': rotate == 0 ? 0 : -scale[0],
'c': rotate == 0 ? 0 : scale[0],
'd': rotate == 0 ? scale[1] || scale[0] : 0,
'e': rotate == 0 ? translate[0] : translate[1],
'f': rotate == 0 ? translate[1] : -translate[0],
}
};
},
Expand Down
47 changes: 47 additions & 0 deletions test/simple-rotation-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import assert from "assert";
import it from "./it.js";
import jsdom from "./jsdom.js";
import * as d3 from "d3-selection";
import * as d3_graphviz from "../index.js";

it("Simple rendering an SVG from graphviz DOT with rotate=90 and zoom disabled.", async () => {
var window = global.window = jsdom('<div id="graph"></div>');
global.document = window.document;

var graphviz;

await new Promise(resolve => {
graphviz = d3_graphviz.graphviz("#graph")
.zoom(false)
.renderDot('digraph {rotate=90; a -> b;}', resolve);
});

assert.equal(d3.selectAll('.node').size(), 2, 'Number of nodes');
assert.equal(d3.selectAll('.edge').size(), 1, 'Number of edges');
assert.equal(d3.selectAll('ellipse').size(), 2, 'Number of ellipses');
assert.equal(d3.selectAll('polygon').size(), 2, 'Number of polygons');
assert.equal(d3.selectAll('path').size(), 1, 'Number of paths');

assert.equal(d3.select('#graph0').attr("transform"), "scale(1 1) rotate(-90) translate(-58 112)");
});

it("Simple rendering an SVG from graphviz DOT with rotate=90 and zoom enabled.", async () => {
var window = global.window = jsdom('<div id="graph"></div>');
global.document = window.document;

var graphviz;

await new Promise(resolve => {
graphviz = d3_graphviz.graphviz("#graph")
.zoom(true)
.renderDot('digraph {rotate=90; a -> b;}', resolve);
});

assert.equal(d3.selectAll('.node').size(), 2, 'Number of nodes');
assert.equal(d3.selectAll('.edge').size(), 1, 'Number of edges');
assert.equal(d3.selectAll('ellipse').size(), 2, 'Number of ellipses');
assert.equal(d3.selectAll('polygon').size(), 2, 'Number of polygons');
assert.equal(d3.selectAll('path').size(), 1, 'Number of paths');

assert.equal(d3.select('#graph0').attr("transform"), "rotate(-90) translate(-58 112) scale(1)");
});
Loading

0 comments on commit 355158d

Please sign in to comment.