draw/TPolyLinePainter.mjs

import { BIT, isStr, clTPolyLine } from '../core.mjs';
import { makeTranslate } from '../base/BasePainter.mjs';
import { ObjectPainter } from '../base/ObjectPainter.mjs';
import { ensureTCanvas } from '../gpad/TCanvasPainter.mjs';
import { addMoveHandler } from '../gui/utils.mjs';
import { assignContextMenu } from '../gui/menu.mjs';


const kPolyLineNDC = BIT(14);

/**
 * @summary Painter for TPolyLine class
 * @private
 */

class TPolyLinePainter extends ObjectPainter {

   #dx; // interactive change
   #dy; // interactive change
   #isndc; // if NDC coordinates used

   /** @summary Dragging object
    *  @private */
   moveDrag(dx, dy) {
      this.#dx += dx;
      this.#dy += dy;
      makeTranslate(this.draw_g.select('path'), this.#dx, this.#dy);
   }

   /** @summary End dragging object
    * @private */
   moveEnd(not_changed) {
      if (not_changed) return;
      const polyline = this.getObject(),
            func = this.getAxisToSvgFunc(this.#isndc);
      let exec = '';

      for (let n = 0; n <= polyline.fLastPoint; ++n) {
         const x = this.svgToAxis('x', func.x(polyline.fX[n]) + this.#dx, this.#isndc),
               y = this.svgToAxis('y', func.y(polyline.fY[n]) + this.#dy, this.#isndc);
         polyline.fX[n] = x;
         polyline.fY[n] = y;
         exec += `SetPoint(${n},${x},${y});;`;
      }
      this.submitCanvExec(exec + 'Notify();;');
      this.redraw();
   }

   /** @summary Returns object ranges
    * @desc Can be used for newly created canvas */
   getUserRanges() {
      const polyline = this.getObject(),
            isndc = polyline.TestBit(kPolyLineNDC);
      if (isndc || !polyline.fLastPoint)
         return null;
      let minx = polyline.fX[0], maxx = minx,
          miny = polyline.fY[0], maxy = miny;
      for (let n = 1; n <= polyline.fLastPoint; ++n) {
         minx = Math.min(minx, polyline.fX[n]);
         maxx = Math.max(maxx, polyline.fX[n]);
         miny = Math.min(miny, polyline.fY[n]);
         maxy = Math.max(maxy, polyline.fY[n]);
      }
      return { minx, miny, maxx, maxy };
   }

   /** @summary Redraw poly line */
   redraw() {
      this.createG();

      const polyline = this.getObject(),
            isndc = polyline.TestBit(kPolyLineNDC),
            opt = this.getDrawOpt() || polyline.fOption,
            dofill = (polyline._typename === clTPolyLine) && (isStr(opt) && opt.toLowerCase().indexOf('f') >= 0),
            func = this.getAxisToSvgFunc(isndc);

      this.createAttLine({ attr: polyline });
      this.createAttFill({ attr: polyline, enable: dofill });

      let cmd = '';
      for (let n = 0; n <= polyline.fLastPoint; ++n)
         cmd += `${n > 0?'L':'M'}${func.x(polyline.fX[n])},${func.y(polyline.fY[n])}`;

      this.draw_g.append('svg:path')
                 .attr('d', cmd + (dofill ? 'Z' : ''))
                 .call(dofill ? () => {} : this.lineatt.func)
                 .call(this.fillatt.func);

      assignContextMenu(this);

      addMoveHandler(this);

      this.#dx = this.#dy = 0;
      this.#isndc = isndc;

      return this;
   }

   /** @summary Draw TPolyLine object */
   static async draw(dom, obj, opt) {
      const painter = new TPolyLinePainter(dom, obj, opt);
      return ensureTCanvas(painter, false).then(() => painter.redraw());
   }

} // class TPolyLinePainter


export { TPolyLinePainter };