Skip to content

Commit

Permalink
Build with lego axis rotations
Browse files Browse the repository at this point in the history
  • Loading branch information
linev committed Nov 7, 2024
1 parent 89c8193 commit 98b4a95
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 45 deletions.
135 changes: 105 additions & 30 deletions build/jsroot.js
Original file line number Diff line number Diff line change
Expand Up @@ -63193,6 +63193,16 @@ class TAxisPainter extends ObjectPainter {
return this.getObject()?.TestBit(EAxisBits.kCenterLabels);
}

/** @summary Is labels should be rotated */
isRotateLabels() {
return this.getObject()?.TestBit(EAxisBits.kLabelsVert);
}

/** @summary Is title should be rotated */
isRotateTitle() {
return this.getObject()?.TestBit(EAxisBits.kRotateTitle);
}

/** @summary Add interactive elements to draw axes title */
addTitleDrag(title_g, vertical, offset_k, reverse, axis_length) {
if (!settings.MoveResize || this.isBatchMode()) return;
Expand Down Expand Up @@ -63396,7 +63406,7 @@ class TAxisPainter extends ObjectPainter {
label_g = [axis_g.append('svg:g').attr('class', 'axis_labels')],
lbl_pos = handle.lbl_pos || handle.major,
tilt_angle = gStyle.AxisTiltAngle ?? 25;
let rotate_lbls = axis.TestBit(EAxisBits.kLabelsVert),
let rotate_lbls = this.isRotateLabels(),
textscale = 1, flipscale = 1, maxtextlen = 0, applied_scale = 0,
lbl_tilt = false, any_modified = false, max_textwidth = 0, max_tiltsize = 0;

Expand Down Expand Up @@ -63786,7 +63796,7 @@ class TAxisPainter extends ObjectPainter {
if (!title_g)
return;

const rotate = axis.TestBit(EAxisBits.kRotateTitle) ? -1 : 1,
const rotate = this.isRotateTitle() ? -1 : 1,
xor_reverse = swap_side ^ this.titleOpposite, myxor = (rotate < 0) ^ xor_reverse;

let title_offest_k = side;
Expand Down Expand Up @@ -80467,7 +80477,7 @@ function drawXYZ(toplevel, AxisPainter, opts) {
top.axis_draw = true; // mark element as axis drawing
toplevel.add(top);

let ticks = [], lbls = [], maxtextheight = 0;
let ticks = [], lbls = [], maxtextheight = 0, maxtextwidth = 0;

while (xticks.next()) {
const grx = xticks.grpos;
Expand All @@ -80492,6 +80502,7 @@ function drawXYZ(toplevel, AxisPainter, opts) {

text3d.offsety = this.x_handle.labelsOffset + (grmaxy - grminy) * 0.005;

maxtextwidth = Math.max(maxtextwidth, draw_width);
maxtextheight = Math.max(maxtextheight, draw_height);

if (mod?.fTextColor) text3d.color = this.getColor(mod.fTextColor);
Expand All @@ -80504,6 +80515,8 @@ function drawXYZ(toplevel, AxisPainter, opts) {
if ((draw_width > 0) && (space > 0))
text_scale = Math.min(text_scale, 0.9*space/draw_width);
}
if (this.x_handle.isRotateLabels())
text3d.rotate = 1;

if (this.x_handle.isCenteredLabels()) {
if (!space) space = Math.min(grx - grminx, grmaxx - grx);
Expand All @@ -80522,6 +80535,9 @@ function drawXYZ(toplevel, AxisPainter, opts) {
text3d.offsety = 1.6 * this.x_handle.titleOffset + (grmaxy - grminy) * 0.005;
text3d.grx = (grminx + grmaxx)/2; // default position for centered title
text3d.kind = 'title';
if (this.x_handle.isRotateTitle())
text3d.rotate = 2;

lbls.push(text3d);
}

Expand Down Expand Up @@ -80648,17 +80664,28 @@ function drawXYZ(toplevel, AxisPainter, opts) {
}

lbls.forEach(lbl => {
const w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
posx = lbl.center ? lbl.grx - w/2 : (lbl.opposite ? grminx : grmaxx - w),
m = new THREE.Matrix4();
const dx = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
dy = lbl.boundingBox.max.y - lbl.boundingBox.min.y,
w = (lbl.rotate === 1) ? dy : dx,
posx = lbl.center ? lbl.grx - w/2 : (lbl.opposite ? grminx : grmaxx - w),
posy = -text_scale * (lbl.rotate === 1 ? maxtextwidth : maxtextheight) - this.x_handle.ticksSize - lbl.offsety,
m = new THREE.Matrix4();

// matrix to swap y and z scales and shift along z to its position
m.set(text_scale, 0, 0, posx,
0, text_scale, 0, -maxtextheight*text_scale - this.x_handle.ticksSize - lbl.offsety,
0, text_scale, 0, posy,
0, 0, 1, 0,
0, 0, 0, 1);

const mesh = new THREE.Mesh(lbl, getTextMaterial(this.x_handle, lbl.kind, lbl.color));

if (lbl.rotate)
mesh.rotateZ(lbl.rotate * Math.PI / 2);
if (lbl.rotate === 1)
mesh.translateY(-dy);
if (lbl.rotate === 2)
mesh.translateX(-dx);

mesh.applyMatrix4(m);
xcont.add(mesh);
});
Expand All @@ -80676,16 +80703,26 @@ function drawXYZ(toplevel, AxisPainter, opts) {
xcont.add(new THREE.LineSegments(xtickslines.geometry, xtickslines.material));

lbls.forEach(lbl => {
const w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
posx = (lbl.center ? lbl.grx + w/2 : lbl.opposite ? grminx + w : grmaxx),
const dx = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
dy = lbl.boundingBox.max.y - lbl.boundingBox.min.y,
w = (lbl.rotate === 1) ? dy : dx,
posx = lbl.center ? lbl.grx + w/2 : (lbl.opposite ? grminx + w: grmaxx),
posy = -text_scale * (lbl.rotate === 1 ? maxtextwidth : maxtextheight) - this.x_handle.ticksSize - lbl.offsety,
m = new THREE.Matrix4();

// matrix to swap y and z scales and shift along z to its position
m.set(-text_scale, 0, 0, posx,
0, text_scale, 0, -maxtextheight*text_scale - this.x_handle.ticksSize - lbl.offsety,
0, text_scale, 0, posy,
0, 0, -1, 0,
0, 0, 0, 1);

const mesh = new THREE.Mesh(lbl, getTextMaterial(this.x_handle, lbl.kind, lbl.color));
if (lbl.rotate)
mesh.rotateZ(lbl.rotate * Math.PI / 2);
if (lbl.rotate === 1)
mesh.translateY(-dy);
if (lbl.rotate === 2)
mesh.translateX(-dx);
mesh.applyMatrix4(m);
xcont.add(mesh);
});
Expand All @@ -80695,7 +80732,10 @@ function drawXYZ(toplevel, AxisPainter, opts) {
xcont.add(createZoomMesh('x', this.size_x3d));
top.add(xcont);

lbls = []; text_scale = 1; maxtextheight = 0; ticks = [];
lbls = [];
text_scale = 1;
maxtextwidth = maxtextheight = 0;
ticks = [];

while (yticks.next()) {
const gry = yticks.grpos;
Expand All @@ -80715,9 +80755,10 @@ function drawXYZ(toplevel, AxisPainter, opts) {
const text3d = createLatexGeometry(this, lbl, this.y_handle.labelsFont.size);
text3d.computeBoundingBox();
const draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
text3d.center = true;

maxtextwidth = Math.max(maxtextwidth, draw_width);
maxtextheight = Math.max(maxtextheight, draw_height);

if (mod?.fTextColor) text3d.color = this.getColor(mod.fTextColor);
Expand All @@ -80735,6 +80776,8 @@ function drawXYZ(toplevel, AxisPainter, opts) {
if (!space) space = Math.min(gry - grminy, grmaxy - gry);
text3d.gry += space/2;
}
if (this.y_handle.isRotateLabels())
text3d.rotate = 1;
}
ticks.push(0, gry, 0, this.y_handle.ticksSize*(is_major ? -1 : -0.6), gry, 0);
}
Expand All @@ -80747,6 +80790,8 @@ function drawXYZ(toplevel, AxisPainter, opts) {
text3d.offsetx = 1.6 * this.y_handle.titleOffset + (grmaxx - grminx) * 0.005;
text3d.gry = (grminy + grmaxy)/2; // default position for centered title
text3d.kind = 'title';
if (this.y_handle.isRotateTitle())
text3d.rotate = 2;
lbls.push(text3d);
}

Expand All @@ -80761,16 +80806,25 @@ function drawXYZ(toplevel, AxisPainter, opts) {
}

lbls.forEach(lbl => {
const w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
posy = lbl.center ? lbl.gry + w/2 : (lbl.opposite ? grminy + w : grmaxy),
m = new THREE.Matrix4();
// matrix to swap y and z scales and shift along z to its position
m.set(0, text_scale, 0, -maxtextheight*text_scale - this.y_handle.ticksSize - lbl.offsetx,
const dx = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
dy = lbl.boundingBox.max.y - lbl.boundingBox.min.y,
w = (lbl.rotate === 1) ? dy : dx,
posx = -text_scale * (lbl.rotate === 1 ? maxtextwidth : maxtextheight) - this.y_handle.ticksSize - lbl.offsetx,
posy = lbl.center ? lbl.gry + w/2 : (lbl.opposite ? grminy + w : grmaxy),
m = new THREE.Matrix4();
m.set(0, text_scale, 0, posx,
-text_scale, 0, 0, posy,
0, 0, 1, 0,
0, 0, 0, 1);

const mesh = new THREE.Mesh(lbl, getTextMaterial(this.y_handle, lbl.kind, lbl.color));
if (lbl.rotate)
mesh.rotateZ(lbl.rotate * Math.PI / 2);
if (lbl.rotate === 1)
mesh.translateY(-dy);
if (lbl.rotate === 2)
mesh.translateX(-dx);

mesh.applyMatrix4(m);
ycont.add(mesh);
});
Expand All @@ -80788,15 +80842,26 @@ function drawXYZ(toplevel, AxisPainter, opts) {
ycont.add(new THREE.LineSegments(yticksline.geometry, yticksline.material));

lbls.forEach(lbl => {
const w = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
posy = lbl.center ? lbl.gry - w/2 : (lbl.opposite ? grminy : grmaxy - w),
m = new THREE.Matrix4();
m.set(0, text_scale, 0, -maxtextheight*text_scale - this.y_handle.ticksSize - lbl.offsetx,
const dx = lbl.boundingBox.max.x - lbl.boundingBox.min.x,
dy = lbl.boundingBox.max.y - lbl.boundingBox.min.y,
w = (lbl.rotate === 1) ? dy : dx,
posx = -text_scale * (lbl.rotate === 1 ? maxtextwidth : maxtextheight) - this.y_handle.ticksSize - lbl.offsetx,
posy = lbl.center ? lbl.gry - w/2 : (lbl.opposite ? grminy : grmaxy - w),
m = new THREE.Matrix4();

m.set(0, text_scale, 0, posx,
text_scale, 0, 0, posy,
0, 0, -1, 0,
0, 0, 0, 1);

const mesh = new THREE.Mesh(lbl, getTextMaterial(this.y_handle, lbl.kind, lbl.color));
if (lbl.rotate)
mesh.rotateZ(lbl.rotate * Math.PI / 2);
if (lbl.rotate === 1)
mesh.translateY(-dy);
if (lbl.rotate === 2)
mesh.translateX(-dx);

mesh.applyMatrix4(m);
ycont.add(mesh);
});
Expand Down Expand Up @@ -80828,7 +80893,7 @@ function drawXYZ(toplevel, AxisPainter, opts) {
const text3d = createLatexGeometry(this, lbl, this.z_handle.labelsFont.size);
text3d.computeBoundingBox();
const draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
draw_height = text3d.boundingBox.max.y - text3d.boundingBox.min.y;
text3d.translate(-draw_width, -draw_height/2, 0);

if (mod?.fTextColor) text3d.color = this.getColor(mod.fTextColor);
Expand Down Expand Up @@ -80890,7 +80955,9 @@ function drawXYZ(toplevel, AxisPainter, opts) {
zcont.push(new THREE.Object3D());

lbls.forEach((lbl, indx) => {
const m = new THREE.Matrix4();
const m = new THREE.Matrix4(),
dx = lbl.boundingBox.max.x - lbl.boundingBox.min.x;

let grz = lbl.grz;

if (this.z_handle.isCenteredLabels()) {
Expand All @@ -80905,23 +80972,28 @@ function drawXYZ(toplevel, AxisPainter, opts) {
0, 0, 1, 0,
0, text_scale, 0, grz);
const mesh = new THREE.Mesh(lbl, getTextMaterial(this.z_handle));
if (this.z_handle.isRotateLabels())
mesh.rotateZ(-Math.PI/2).translateX(dx/2);
mesh.applyMatrix4(m);
zcont[n].add(mesh);
});

if (this.z_handle.fTitle && opts.draw) {
const text3d = createLatexGeometry(this, this.z_handle.fTitle, this.z_handle.titleFont.size);
text3d.computeBoundingBox();
const draw_width = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
posz = this.z_handle.titleCenter ? (grmaxz + grminz - draw_width)/2 : (this.z_handle.titleOpposite ? grminz : grmaxz - draw_width);

text3d.rotateZ(Math.PI/2);
const dx = text3d.boundingBox.max.x - text3d.boundingBox.min.x,
dy = text3d.boundingBox.max.y - text3d.boundingBox.min.y,
rotate = this.z_handle.isRotateTitle(),
posz = this.z_handle.titleCenter ? (grmaxz + grminz - dx)/2 : (this.z_handle.titleOpposite ? grminz : grmaxz - dx) + (rotate ? dx : 0),
m = new THREE.Matrix4();

const m = new THREE.Matrix4();
m.set(-text_scale, 0, 0, this.z_handle.ticksSize + (grmaxx - grminx) * 0.005 + maxzlblwidth + this.z_handle.titleOffset,
0, 0, 1, 0,
0, text_scale, 0, posz);
const mesh = new THREE.Mesh(text3d, getTextMaterial(this.z_handle, 'title'));
mesh.rotateZ(Math.PI*(rotate ? 1.5 : 0.5));
if (rotate) mesh.translateY(-dy);

mesh.applyMatrix4(m);
zcont[n].add(mesh);
}
Expand Down Expand Up @@ -83430,7 +83502,7 @@ function drawTH2PolyLego(painter) {
geometry.setAttribute('position', new THREE.BufferAttribute(pos, 3));
geometry.computeVertexNormals();

const material = new THREE.MeshBasicMaterial(getMaterialArgs(painter._color_palette?.getColor(colindx), { vertexColors: false })),
const material = new THREE.MeshBasicMaterial(getMaterialArgs(painter._color_palette?.getColor(colindx), { vertexColors: false, side: THREE.DoubleSide })),
mesh = new THREE.Mesh(geometry, material);

pmain.add3DMesh(mesh);
Expand Down Expand Up @@ -148524,7 +148596,7 @@ let TGraphPainter$1 = class TGraphPainter extends ObjectPainter {
rect = { x1: -5, x2: 5, y1: -5, y2: 5 };

const matchx = (pnt.x >= d.grx1 + rect.x1) && (pnt.x <= d.grx1 + rect.x2),
matchy = (pnt.y >= d.gry1 + rect.y1) && (pnt.y <= d.gry1 + rect.y2);
matchy = (pnt.y >= d.gry1 + rect.y1) && (pnt.y <= d.gry1 + rect.y2);

if (matchx && (matchy || (pnt.nproc > 1))) {
best_dist2 = dist2;
Expand Down Expand Up @@ -156715,6 +156787,9 @@ class RAxisPainter extends RObjectPainter {
return this.v7EvalAttr('labels_center', false);
}

/** @summary Is labels should be rotated */
isRotateLabels() { return false; }

/** @summary Used to move axis labels instead of zooming
* @private */
processLabelsMove(arg, pos) {
Expand Down
31 changes: 16 additions & 15 deletions changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
1. Let use custom time zone for time display, support '&utc' and '&cet' in URL parameters
2. Support gStyle.fLegendFillStyle
3. Let change histogram min/max values via context menu
4. Support Z-scale zooming with TScatter
4. Support Z-scale zooming with `TScatter`
5. Implement "haxis" draw option for histogram to draw only axes for hbar
6. Implement "axisg" and "haxisg" to draw axes with grids
7. Support TH1 marker, text and line drawing superimposed with "haxis"
7. Support `TH1` marker, text and line drawing superimposed with "haxis"
8. Support `TBox`, `TLatex`, `TLine`, `TMarker` drawing on "frame", support drawing on swapped axes
9. `TProfile` and `TProfile2D` projections https://github.com/root-project/root/issues/15851
10. Draw total histogram from TEfficiency when draw option starts with 'b'
11. Let redraw TEfficiency, THStack and TMultiGraph with different draw options via hist context menu
12. Support 'pads' draw options for TMultiGraph, support context menu for it
13. Let drop object on sub-pads
10. Draw total histogram from `TEfficiency` when draw option starts with 'b'
11. Let redraw `TEfficiency`, `THStack` and `TMultiGraph` with different draw options via hist context menu
12. Support 'pads' draw options for `TMultiGraph`, support context menu for it
13. Let drop objects on sub-pads
14. Properly loads ES6 modules for web canvas
15. Improve performance of TH3/RH3 drawing by using THREE.InstancedMesh
15. Improve performance of `TH3`/`RH3` drawing by using THREE.InstancedMesh
16. Implement batch mode with '&batch' URL parameter to create SVG/PNG images with default GUI
17. Adjust node.js implementation to produce identical output with normal browser
18. Create necessary infrastructure for testing with 'puppeteer'
Expand All @@ -29,15 +29,16 @@
26. Create unified svg2pdf/jspdf ES6 modules, integrate in jsroot builds
27. Let create multipage PDF document - in TWebCanvas batch mode
28. Let add external links via `#url[link]{label}` syntax - including jsPDF support
29. Support TAttMarker style with line width bigger than 1
29. Support `TAttMarker` style with line width bigger than 1
30. Provide link to ROOT class documentation from context menus
31. Internals - upgrade to eslint 9
32. Internals - do not select pad (aka gPad) for objects drawing, always use assigned pad painter
33. Fix - properly save zoomed ranges in drawingJSON()
34. Fix - properly redraw `TMultiGraph`
35. Fix - show empty bin in `TProfile2D` if it has entries #316
36. Fix - unzooming on log scale was extending range forevever
37. Fix - display empty hist bin if fSumw2 not zero
31. Implement axis labels and title rotations on lego plots
32. Internals - upgrade to eslint 9
33. Internals - do not select pad (aka gPad) for objects drawing, always use assigned pad painter
34. Fix - properly save zoomed ranges in drawingJSON()
35. Fix - properly redraw `TMultiGraph`
36. Fix - show empty bin in `TProfile2D` if it has entries #316
37. Fix - unzooming on log scale was extending range forevever
38. Fix - display empty hist bin if fSumw2 not zero


## Changes in 7.7.5
Expand Down

0 comments on commit 98b4a95

Please sign in to comment.