UNPKG

jsroot

Version:
287 lines (235 loc) 9.02 kB
import { BIT } from '../core.mjs'; import { BasePainter, makeTranslate, DrawOptions } from '../base/BasePainter.mjs'; import { addMoveHandler } from '../gui/utils.mjs'; import { assignContextMenu } from '../gui/menu.mjs'; /** @summary Draw TEllipse * @private */ function drawEllipse() { const ellipse = this.getObject(), closed_ellipse = (ellipse.fPhimin === 0) && (ellipse.fPhimax === 360), is_crown = (ellipse._typename === 'TCrown'); this.createAttLine({ attr: ellipse }); this.createAttFill({ attr: ellipse }); const g = this.createG(), funcs = this.getAxisToSvgFunc(), x = funcs.x(ellipse.fX1), y = funcs.y(ellipse.fY1), rx = is_crown && (ellipse.fR1 <= 0) ? (funcs.x(ellipse.fX1 + ellipse.fR2) - x) : (funcs.x(ellipse.fX1 + ellipse.fR1) - x), ry = y - funcs.y(ellipse.fY1 + ellipse.fR2), dr = Math.PI / 180; let path = ''; if (is_crown && (ellipse.fR1 > 0)) { const ratio = ellipse.fYXRatio ?? 1, rx1 = rx, ry2 = ratio * ry, ry1 = ratio * (y - funcs.y(ellipse.fY1 + ellipse.fR1)), rx2 = funcs.x(ellipse.fX1 + ellipse.fR2) - x; if (closed_ellipse) { path = `M${-rx1},0A${rx1},${ry1},0,1,0,${rx1},0A${rx1},${ry1},0,1,0,${-rx1},0` + `M${-rx2},0A${rx2},${ry2},0,1,0,${rx2},0A${rx2},${ry2},0,1,0,${-rx2},0`; } else { const large_arc = (ellipse.fPhimax - ellipse.fPhimin >= 180) ? 1 : 0, a1 = ellipse.fPhimin * dr, a2 = ellipse.fPhimax * dr, dx1 = Math.round(rx1 * Math.cos(a1)), dy1 = Math.round(ry1 * Math.sin(a1)), dx2 = Math.round(rx1 * Math.cos(a2)), dy2 = Math.round(ry1 * Math.sin(a2)), dx3 = Math.round(rx2 * Math.cos(a1)), dy3 = Math.round(ry2 * Math.sin(a1)), dx4 = Math.round(rx2 * Math.cos(a2)), dy4 = Math.round(ry2 * Math.sin(a2)); path = `M${dx2},${dy2}A${rx1},${ry1},0,${large_arc},0,${dx1},${dy1}` + `L${dx3},${dy3}A${rx2},${ry2},0,${large_arc},1,${dx4},${dy4}Z`; } } else if (ellipse.fTheta === 0) { if (closed_ellipse) path = `M${-rx},0A${rx},${ry},0,1,0,${rx},0A${rx},${ry},0,1,0,${-rx},0Z`; else { const x1 = Math.round(rx * Math.cos(ellipse.fPhimin * dr)), y1 = Math.round(ry * Math.sin(ellipse.fPhimin * dr)), x2 = Math.round(rx * Math.cos(ellipse.fPhimax * dr)), y2 = Math.round(ry * Math.sin(ellipse.fPhimax * dr)); path = `M0,0L${x1},${y1}A${rx},${ry},0,1,1,${x2},${y2}Z`; } } else { const ct = Math.cos(ellipse.fTheta * dr), st = Math.sin(ellipse.fTheta * dr), phi1 = ellipse.fPhimin * dr, phi2 = ellipse.fPhimax * dr, np = 200, dphi = (phi2 - phi1) / (np - (closed_ellipse ? 0 : 1)); let lastx = 0, lasty = 0; if (!closed_ellipse) path = 'M0,0'; for (let n = 0; n < np; ++n) { const angle = phi1 + n * dphi, dx = ellipse.fR1 * Math.cos(angle), dy = ellipse.fR2 * Math.sin(angle), px = funcs.x(ellipse.fX1 + dx * ct - dy * st) - x, py = funcs.y(ellipse.fY1 + dx * st + dy * ct) - y; if (!path) path = `M${px},${py}`; else if (lastx === px) path += `v${py - lasty}`; else if (lasty === py) path += `h${px - lastx}`; else path += `l${px - lastx},${py - lasty}`; lastx = px; lasty = py; } path += 'Z'; } this.x = x; this.y = y; makeTranslate(g.append('svg:path'), x, y) .attr('d', path) .call(this.lineatt.func) .call(this.fillatt.func); assignContextMenu(this); addMoveHandler(this); this.moveDrag = function(dx, dy) { this.x += dx; this.y += dy; makeTranslate(this.getG().select('path'), this.x, this.y); }; this.moveEnd = function(not_changed) { if (not_changed) return; const ell = this.getObject(); ell.fX1 = this.svgToAxis('x', this.x); ell.fY1 = this.svgToAxis('y', this.y); this.submitCanvExec(`SetX1(${ell.fX1});;SetY1(${ell.fY1});;Notify();;`); }; } /** @summary Draw TPie * @private */ function drawPie() { const g = this.createG(), pie = this.getObject(), nb = pie.fPieSlices.length, xc = this.axisToSvg('x', pie.fX), yc = this.axisToSvg('y', pie.fY), rx = this.axisToSvg('x', pie.fX + pie.fRadius) - xc, ry = this.axisToSvg('y', pie.fY + pie.fRadius) - yc; makeTranslate(g, xc, yc); // Draw the slices let total = 0, af = (pie.fAngularOffset * Math.PI) / 180, x1 = Math.round(rx * Math.cos(af)), y1 = Math.round(ry * Math.sin(af)); for (let n = 0; n < nb; n++) total += pie.fPieSlices[n].fValue; for (let n = 0; n < nb; n++) { const slice = pie.fPieSlices[n]; this.createAttLine({ attr: slice }); this.createAttFill({ attr: slice }); af += slice.fValue / total * 2 * Math.PI; const x2 = Math.round(rx * Math.cos(af)), y2 = Math.round(ry * Math.sin(af)); g.append('svg:path') .attr('d', `M0,0L${x1},${y1}A${rx},${ry},0,0,0,${x2},${y2}z`) .call(this.lineatt.func) .call(this.fillatt.func); x1 = x2; y1 = y2; } } /** @summary Draw TMarker * @private */ function drawMarker() { const marker = this.getObject(), kMarkerNDC = BIT(14); this.isndc = marker.TestBit(kMarkerNDC); const d = new DrawOptions(this.getDrawOpt()), use_frame = this.isndc ? false : d.check('FRAME'), swap_xy = use_frame && this.getFramePainter()?.swap_xy(); this.createAttMarker({ attr: marker }); const g = this.createG(use_frame ? 'frame2d' : undefined); let x = this.axisToSvg('x', marker.fX, this.isndc), y = this.axisToSvg('y', marker.fY, this.isndc); if (swap_xy) [x, y] = [y, x]; const path = this.markeratt.create(x, y); if (path) { g.append('svg:path') .attr('d', path) .call(this.markeratt.func); } if (d.check('NO_INTERACTIVE')) return; assignContextMenu(this); addMoveHandler(this); this.dx = this.dy = 0; this.moveDrag = function(dx, dy) { this.dx += dx; this.dy += dy; if (this.getG()) makeTranslate(this.getG().select('path'), this.dx, this.dy); }; this.moveEnd = function(not_changed) { if (not_changed || !this.getG()) return; const mrk = this.getObject(); let fx = this.svgToAxis('x', this.axisToSvg('x', mrk.fX, this.isndc) + this.dx, this.isndc), fy = this.svgToAxis('y', this.axisToSvg('y', mrk.fY, this.isndc) + this.dy, this.isndc); if (swap_xy) [fx, fy] = [fy, fx]; mrk.fX = fx; mrk.fY = fy; this.submitCanvExec(`SetX(${fx});;SetY(${fy});;Notify();;`); this.redraw(); }; } /** @summary Draw TPolyMarker * @private */ function drawPolyMarker() { const poly = this.getObject(), func = this.getAxisToSvgFunc(); this.createAttMarker({ attr: poly }); const g = this.createG(); let path = ''; for (let n = 0; n <= poly.fLastPoint; ++n) path += this.markeratt.create(func.x(poly.fX[n]), func.y(poly.fY[n])); if (path) { g.append('svg:path') .attr('d', path) .call(this.markeratt.func); } assignContextMenu(this); addMoveHandler(this); this.dx = this.dy = 0; this.moveDrag = function(dx, dy) { this.dx += dx; this.dy += dy; if (this.getG()) makeTranslate(this.getG().select('path'), this.dx, this.dy); }; this.moveEnd = function(not_changed) { if (not_changed || !this.getG()) return; const poly2 = this.getObject(), func2 = this.getAxisToSvgFunc(); let exec = ''; for (let n = 0; n <= poly2.fLastPoint; ++n) { const x = this.svgToAxis('x', func2.x(poly2.fX[n]) + this.dx), y = this.svgToAxis('y', func2.y(poly2.fY[n]) + this.dy); poly2.fX[n] = x; poly2.fY[n] = y; exec += `SetPoint(${n},${x},${y});;`; } this.submitCanvExec(exec + 'Notify();;'); this.redraw(); }; } /** @summary Draw JS image * @private */ function drawJSImage(dom, obj, opt) { const painter = new BasePainter(dom), main = painter.selectDom(), img = main.append('img').attr('src', obj.fName).attr('title', obj.fTitle || obj.fName); if (opt && opt.indexOf('scale') >= 0) img.style('width', '100%').style('height', '100%'); else if (opt && opt.indexOf('center') >= 0) { main.style('position', 'relative'); img.attr('style', 'margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);'); } painter.setTopPainter(); return painter; } export { drawEllipse, drawPie, drawMarker, drawPolyMarker, drawJSImage };