Ignore:
Timestamp:
12/12/24 17:06:06 (5 weeks ago)
Author:
stefan toskovski <stefantoska84@…>
Branches:
main
Parents:
d565449
Message:

Pred finalna verzija

File:
1 edited

Legend:

Unmodified
Added
Removed
  • imaps-frontend/src/scripts/main/MapBuilder.js

    rd565449 r0c6b92a  
    22import Konva from "konva";
    33import HttpService from "../net/HttpService.js";
    4 import { zoomStage } from "../util/zoomStage.js";
     4import {zoomStage} from "../util/zoomStage.js";
     5import {addEventHandling} from "../util/addEventHandling.js";
     6import MapNode from "../base/MapNode.js";
     7import {json} from "react-router-dom";
     8import log from "eslint-plugin-react/lib/util/log.js";
     9import ShapeRegistry from "../util/ShapeRegistry.js";
     10import shapeRegistry from "../util/ShapeRegistry.js";
     11import triggerMapSave from "../util/triggerMapSave.js";
    512
    613export class MapBuilder {
    7   constructor(containerId) {
    8     this.container = document.getElementById(containerId);
    9     this.stage = new Konva.Stage({
    10       container: containerId,
    11       width: this.container.clientWidth,
    12       height: this.container.clientHeight,
    13     });
    14 
    15     // TODO AKO DRAGNIT NEKOJ OD POCETOK NA STAGE POZICIIVE KE SA ZEZNAT
    16     // TODO jwt vo cookie
    17     // TODO placed shape i mouseMoveHandler da ne callback ( da ne vrakjat funkcija)
    18 
    19     this.gridLayer = new Konva.Layer();
    20     this.mainLayer = new Konva.Layer();
    21     this.dragLayer = new Konva.Layer();
    22     this.infoPinLayer = new Konva.Layer();
    23     this.textLayer = new Konva.Layer();
    24     this.gridLayer.listening(false);
    25 
    26     this.originalWidth = this.container.clientWidth;
    27     this.originalHeight = this.container.clientHeight;
    28 
    29     this.shapes = [];
    30     this.blockSize = 10;
    31     this.efficientDrawingMode = false;
    32     this.roomTypes = [];
    33 
    34     this.gridLine = new Konva.Line({
    35       points: [],
    36       stroke: "grey",
    37       strokeWidth: 1,
    38       opacity: 0.3,
    39     });
    40 
    41     this.gridLine.cache();
    42 
    43     this.mainTransformer = new Konva.Transformer({
    44       centeredScaling: false,
    45       rotationSnaps: [0, 90, 180, 270],
    46       anchorSize: 5,
    47       padding: 2,
    48       anchorFill: "#ef7539",
    49       borderStroke: "black",
    50       anchorStroke: "black",
    51       cornerRadius: 20,
    52       anchorCornerRadius: 10,
    53       anchorDragBoundFunc: this.transformerSnapFunc(),
    54     });
    55 
    56     this.selectionRectangle = new Konva.Rect({
    57       fill: "rgba(200,0,255,0.5)",
    58       visible: false,
    59       listening: false,
    60       zIndex: 100,
    61     });
    62 
    63     this.x1 = 0;
    64     this.y1 = 0;
    65     this.x2 = 0;
    66     this.y2 = 0;
    67 
    68     this.selecting = false;
    69 
    70     this.initialize();
    71   }
    72 
    73   initialize() {
    74     this.drawGrid();
    75     this.mainLayer.add(this.mainTransformer);
    76     this.mainLayer.add(this.selectionRectangle);
    77     this.stage.add(this.gridLayer);
    78     this.stage.add(this.dragLayer);
    79     this.stage.add(this.mainLayer);
    80     this.stage.add(this.infoPinLayer);
    81     this.stage.add(this.textLayer);
    82     this.setupEventListeners();
    83   }
    84 
    85   setupEventListeners() {
    86     document.getElementById("shapeOptions").addEventListener("click", this.selectShape.bind(this));
    87     document.getElementById("render-button").addEventListener("click", this.render.bind(this));
    88     window.addEventListener("keydown", this.handleExitSelection.bind(this));
    89     window.addEventListener("keydown", this.handleDelete.bind(this));
    90     window.addEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
    91     window.addEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
    92     window.addEventListener("resize", this.handleResize.bind(this));
    93     this.stage.on("mousedown touchstart", this.handleMouseDown.bind(this));
    94     this.stage.on("mousemove touchmove", this.handleMouseMove.bind(this));
    95     this.stage.on("mouseup touchend", this.handleMouseUp.bind(this));
    96     this.stage.on("click tap", this.handleStageClick.bind(this));
    97     this.stage.on("contextmenu", this.placeInfoPin.bind(this));
    98     this.stage.on("dragmove", this.dragStage.bind(this));
    99     this.stage.on("wheel", this.zoom.bind(this));
    100   }
    101 
    102   detachKeyPressEventListeners() {
    103     window.removeEventListener("keydown", this.handleExitSelection.bind(this));
    104     window.removeEventListener("keydown", this.handleDelete.bind(this));
    105     window.removeEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
    106     window.removeEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
    107   }
    108   attachKeyPressEventListeners() {
    109     window.addEventListener("keydown", this.handleExitSelection.bind(this));
    110     window.addEventListener("keydown", this.handleDelete.bind(this));
    111     window.addEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
    112     window.addEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
    113   }
    114 
    115   dragStage(e) {
    116     if (!e.evt.shiftKey) return;
    117     this.drawGrid();
    118   }
    119 
    120   transformerSnapFunc() {
    121     return (oldPos, newPos) => {
    122       const snapDistance = 8;
    123 
    124       if (this.mainTransformer.getActiveAnchor() === "rotater") {
    125         return newPos;
    126       }
    127 
    128       const distance = Math.sqrt(Math.pow(newPos.x - oldPos.x, 2) + Math.pow(newPos.y - oldPos.y, 2));
    129 
    130       if (distance > snapDistance) {
    131         return newPos;
    132       }
    133 
    134       const nextX = Math.round(newPos.x / this.blockSize) * this.blockSize;
    135       const diffX = Math.abs(newPos.x - nextX);
    136 
    137       const nextY = Math.round(newPos.y / this.blockSize) * this.blockSize;
    138       const diffY = Math.abs(newPos.y - nextY);
    139 
    140       const snapToX = diffX < snapDistance;
    141       const snapToY = diffY < snapDistance;
    142 
    143       if (snapToX && !snapToY) {
     14    constructor(containerId,floorNum,mapName) {
     15        this.container = document.getElementById(containerId);
     16        this.stage = new Konva.Stage({
     17            container: containerId,
     18            width: this.container.clientWidth,
     19            height: this.container.clientHeight,
     20        });
     21
     22        // TODO AKO DRAGNIT NEKOJ OD POCETOK NA STAGE POZICIIVE KE SA ZEZNAT
     23        // TODO jwt vo cookie
     24        // TODO placed shape i mouseMoveHandler da ne callback ( da ne vrakjat funkcija)
     25        // TODO text na top layer sekogas
     26
     27        this._floorNum = floorNum;
     28        this.mapName = mapName;
     29
     30        this.gridLayer = new Konva.Layer();
     31        this.mainLayer = new Konva.Layer();
     32        this.dragLayer = new Konva.Layer();
     33        this.infoPinLayer = new Konva.Layer();
     34        this.prioLayer = new Konva.Layer();
     35        this.textLayer = new Konva.Layer();
     36        this.gridLayer.listening(false);
     37
     38
     39        this.othStairs = [];
     40
     41        this.blockSize = 10;
     42        this.efficientDrawingMode = false;
     43        this.roomTypes = [];
     44
     45        this.gridLine = new Konva.Line({
     46            points: [],
     47            stroke: "grey",
     48            strokeWidth: 1,
     49            opacity: 0.3,
     50        });
     51
     52        this.gridLine.cache();
     53
     54        this.mainTransformer = new Konva.Transformer({
     55            centeredScaling: false,
     56            rotationSnaps: [0, 90, 180, 270],
     57            anchorSize: 5,
     58            padding: 2,
     59            anchorFill: "#f6031f",
     60            borderStroke: "black",
     61            anchorStroke: "black",
     62            cornerRadius: 20,
     63            anchorCornerRadius: 10,
     64            anchorDragBoundFunc: this.transformerSnapFunc(),
     65        });
     66
     67        this.selectionRectangle = new Konva.Rect({
     68            fill: "rgba(56,194,245,0.5)",
     69            visible: false,
     70            listening: false,
     71            zIndex: 100,
     72        });
     73
     74        this.x1 = 0;
     75        this.y1 = 0;
     76        this.x2 = 0;
     77        this.y2 = 0;
     78
     79        this.selecting = false;
     80
     81        this.initialize();
     82    }
     83
     84    initialize() {
     85        this.drawGrid();
     86        this.mainLayer.add(this.mainTransformer);
     87        this.mainLayer.add(this.selectionRectangle);
     88        this.stage.add(this.gridLayer);
     89        this.stage.add(this.dragLayer);
     90        this.stage.add(this.mainLayer);
     91        this.stage.add(this.infoPinLayer);
     92        this.stage.add(this.textLayer);
     93        this.setupEventListeners();
     94    }
     95
     96    setupEventListeners() {
     97        document.getElementById("shapeOptions").addEventListener("click", this.selectShape.bind(this));
     98        window.addEventListener("keydown", this.handleExitSelection.bind(this));
     99        window.addEventListener("keydown", this.handleDelete.bind(this));
     100        window.addEventListener("keydown", this.rotateShapesBy90Deg.bind(this));
     101        window.addEventListener("keydown", this.toggleEfficientDrawingMode.bind(this));
     102        window.addEventListener("resize", this.handleResize.bind(this));
     103
     104        this.boundEscapeEventListener = this.handleExitSelection.bind(this);
     105        this.boundDeleteEventListener = this.handleDelete.bind(this);
     106        this.boundRotateShapeEventListener = this.rotateShapesBy90Deg.bind(this)
     107        this.boundEfficientDrawingModeEventListener = this.toggleEfficientDrawingMode.bind(this);
     108
     109        //this.attachKeyPressEventListeners();
     110
     111        this.stage.on("mousedown touchstart", this.handleMouseDown.bind(this));
     112        this.stage.on("mousemove touchmove", this.handleMouseMove.bind(this));
     113        this.stage.on("mouseup touchend", this.handleMouseUp.bind(this));
     114        this.stage.on("click tap", this.handleStageClick.bind(this));
     115        this.stage.on("contextmenu", this.placeInfoPin.bind(this));
     116        this.stage.on("dragmove", this.dragStage.bind(this));
     117        this.stage.on("wheel", this.zoom.bind(this));
     118    }
     119
     120    detachKeyPressEventListeners() {
     121        window.removeEventListener("keydown", this.boundEscapeEventListener);
     122        window.removeEventListener("keydown", this.boundDeleteEventListener);
     123        window.removeEventListener("keydown", this.boundRotateShapeEventListener);
     124        window.removeEventListener("keydown", this.boundEfficientDrawingModeEventListener);
     125    }
     126
     127    attachKeyPressEventListeners() {
     128        window.addEventListener("keydown", this.boundEscapeEventListener);
     129        window.addEventListener("keydown", this.boundDeleteEventListener);
     130        window.addEventListener("keydown", this.boundRotateShapeEventListener);
     131        window.addEventListener("keydown", this.boundEfficientDrawingModeEventListener);
     132    }
     133
     134    dragStage(e) {
     135        if (!e.evt.shiftKey) return;
     136        this.drawGrid();
     137    }
     138
     139    transformerSnapFunc() {
     140        return (oldPos, newPos) => {
     141            const snapDistance = 8;
     142
     143            if (this.mainTransformer.getActiveAnchor() === "rotater") {
     144                return newPos;
     145            }
     146
     147            const distance = Math.sqrt(Math.pow(newPos.x - oldPos.x, 2) + Math.pow(newPos.y - oldPos.y, 2));
     148
     149            if (distance > snapDistance) {
     150                return newPos;
     151            }
     152
     153            const nextX = Math.round(newPos.x / this.blockSize) * this.blockSize;
     154            const diffX = Math.abs(newPos.x - nextX);
     155
     156            const nextY = Math.round(newPos.y / this.blockSize) * this.blockSize;
     157            const diffY = Math.abs(newPos.y - nextY);
     158
     159            const snapToX = diffX < snapDistance;
     160            const snapToY = diffY < snapDistance;
     161
     162            if (snapToX && !snapToY) {
     163                return {
     164                    x: nextX,
     165                    y: oldPos.y,
     166                };
     167            } else if (!snapToX && snapToY) {
     168                return {
     169                    x: oldPos.x,
     170                    y: nextY,
     171                };
     172            } else if (snapToX && snapToY) {
     173                return {
     174                    x: nextX,
     175                    y: nextY,
     176                };
     177            }
     178
     179            return newPos;
     180        };
     181    }
     182
     183    handleResize() {
     184        this.stage.width(this.container.offsetWidth);
     185        this.stage.height(this.container.offsetHeight);
     186        this.drawGrid();
     187    }
     188
     189    zoom(e) {
     190        zoomStage(e, this.stage, true);
     191        this.drawGrid();
     192    }
     193
     194    get floorNum(){
     195        return this._floorNum;
     196    }
     197
     198    set floorNum(val){
     199        this._floorNum = val;
     200    }
     201
     202    drawGrid() {
     203        this.gridLayer.destroyChildren();
     204
     205        let width = this.stage.width();
     206        let height = this.stage.height();
     207
     208        //presmetka od globalen koordinaten sistem vo lokalen na canvasot
     209        let transform = this.stage.getAbsoluteTransform().copy().invert();
     210        let topLeft = transform.point({
     211            x: 0,
     212            y: 0,
     213        });
     214
     215        let bottomRight = transform.point({
     216            x: width,
     217            y: height,
     218        });
     219
     220        let startX = Math.floor(topLeft.x / this.blockSize) * this.blockSize;
     221        let startY = Math.floor(topLeft.y / this.blockSize) * this.blockSize;
     222
     223        let endX = Math.ceil(bottomRight.x / this.blockSize) * this.blockSize;
     224        let endY = Math.ceil(bottomRight.y / this.blockSize) * this.blockSize;
     225
     226        for (let x = startX; x <= endX; x += this.blockSize) {
     227            let line = this.gridLine.clone({
     228                points: [x + 0.5, topLeft.y - this.blockSize, x + 0.5, bottomRight.y + this.blockSize],
     229            });
     230
     231            line.transformsEnabled("position");
     232            line.perfectDrawEnabled(false);
     233            line.shadowForStrokeEnabled(false);
     234
     235            this.gridLayer.add(line);
     236        }
     237
     238        for (let y = startY; y <= endY; y += this.blockSize) {
     239            let line = this.gridLine.clone({
     240                points: [topLeft.x - this.blockSize, y + 0.5, bottomRight.x + this.blockSize, y + 0.5],
     241            });
     242
     243            line.perfectDrawEnabled(false);
     244            line.shadowForStrokeEnabled(false);
     245            line.transformsEnabled("position");
     246            this.gridLayer.add(line);
     247        }
     248
     249        this.mainLayer.moveToTop();
     250        this.infoPinLayer.moveToTop();
     251
     252        this.gridLayer.batchDraw();
     253    }
     254
     255    placeInfoPin(e) {
     256        e.evt.preventDefault();
     257        let mousePos = this.stage.getRelativePointerPosition();
     258        const attrs = {
     259            type: "InfoPin",
     260            position: mousePos,
     261            blockSize: this.blockSize,
     262            layer: this.mainLayer,
     263            rotation: 0,
     264            scaleX: 1,
     265            scaleY: 1,
     266            increment: true,
     267            floorNum: this.floorNum
     268        };
     269        let infoPin = Factory.createShape("InfoPin", attrs);
     270        addEventHandling(infoPin, this, "dblclick");
     271        //this.shapes.push(infoPin);
     272        ShapeRegistry.add(infoPin)
     273        this.mainLayer.add(infoPin);
     274        infoPin.displayName(this.textLayer);
     275        triggerMapSave()
     276
     277        console.log(infoPin.name());
     278    }
     279
     280    toggleEfficientDrawingMode(e) {
     281        if (e.key === "e" || e.key === "E") {
     282            this.efficientDrawingMode = !this.efficientDrawingMode;
     283            console.log("EFFICIENT DRAWING MODE is: ", this.efficientDrawingMode);
     284
     285            if (!this.efficientDrawingMode) {
     286                this.stopDrawing();
     287            }
     288        }
     289    }
     290
     291    placeShape() {
     292        const mousePos = this.stage.getRelativePointerPosition();
     293        const attrs = {
     294            position: mousePos,
     295            width: this.blockSize,
     296            height: this.blockSize,
     297            layer: this.mainLayer,
     298            rotation: this.hoverObj.rotation(),
     299            scaleX: 1,
     300            scaleY: 1,
     301            increment: true,
     302            snap: true,
     303            fromLoad: false,
     304            blockSize: this.blockSize,
     305            floorNum: this.floorNum
     306        };
     307
     308        const placedObj = Factory.createShape(this.hoverObj.type, attrs);
     309        if (!placedObj) return;
     310
     311        console.info("ATTRS FNUM",attrs.floorNum)
     312
     313        this.mainLayer.add(placedObj);
     314        //this.shapes.push(placedObj);
     315        console.log("VO PLACED SHAEPS WALL ZITI SE: " + placedObj.className);
     316        ShapeRegistry.add(placedObj);
     317        addEventHandling(placedObj, this, "dblclick");
     318        this.mainLayer.draw();
     319
     320        // site ovie func da se vo edna funkcija vo shape.
     321
     322        placedObj.displayName(this.textLayer);
     323        placedObj.snapToGrid();
     324
     325        triggerMapSave();
     326
     327        if (!this.efficientDrawingMode) {
     328            this.stopDrawing();
     329        }
     330    }
     331
     332    stopDrawing() {
     333        this.mainTransformer.nodes([]);
     334        if (this.hoverObj != null) this.hoverObj.remove();
     335        this.dragLayer.removeChildren();
     336        this.stage.off("mousemove", this.boundMouseMoveHandler);
     337        this.stage.off("click", this.boundPlaceShapeHandler);
     338    }
     339
     340    mouseMoveHandler() {
     341        const mousePos = this.stage.getRelativePointerPosition();
     342        this.hoverObj.position({x: mousePos.x, y: mousePos.y});
     343        this.hoverObj.visible(true);
     344    }
     345
     346    startDrawing(shapeType) {
     347        const attrs = {
     348            position: {x: 0, y: 0},
     349            width: this.blockSize,
     350            height: this.blockSize,
     351            layer: this.mainLayer,
     352            rotation: 0,
     353            scaleX: 1,
     354            scaleY: 1,
     355            increment: false,
     356            snap: true,
     357            fromLoad: false,
     358            blockSize: this.blockSize
     359        };
     360        this.hoverObj = Factory.createShape(shapeType, attrs);
     361
     362        console.log("HOVBER OBK:", this.hoverObj)
     363
     364        this.hoverObj.visible(false);
     365        this.dragLayer.add(this.hoverObj);
     366        this.dragLayer.moveToTop();
     367        this.boundMouseMoveHandler = this.mouseMoveHandler.bind(this);
     368        this.boundPlaceShapeHandler = this.placeShape.bind(this);
     369
     370        this.stage.on("mousemove", this.boundMouseMoveHandler);
     371        this.stage.on("click", this.boundPlaceShapeHandler);
     372    }
     373
     374    selectShape(e) {
     375        if (e.target.tagName === "LI") {
     376            const shapeType = e.target.getAttribute("data-info");
     377            this.startDrawing(shapeType);
     378            this.mainTransformer.nodes([]);
     379        }
     380    }
     381
     382    rotateShapesBy90Deg(e) {
     383        if (e.key === "r" || e.key === "R") {
     384            if (this.hoverObj) {
     385                this.hoverObj.rotate(90);
     386            }
     387            this.mainTransformer.nodes().forEach((node) => {
     388                node.rotate(90);
     389            });
     390        }
     391    }
     392
     393    handleDelete(e) {
     394        if (e.key === "Delete") {
     395            this.mainTransformer.nodes().forEach((node) => {
     396                node.remove();
     397                node.destroy();
     398                ShapeRegistry.delete(node);
     399                triggerMapSave();
     400            });
     401            this.mainTransformer.nodes([]);
     402            this.mainLayer.batchDraw();
     403        }
     404    }
     405
     406    handleExitSelection(e) {
     407        if (e.key === "Escape") {
     408            this.mainTransformer.nodes([]);
     409            this.stopDrawing();
     410        }
     411    }
     412
     413    handleMouseDown(e) {
     414        this.stage.draggable(e.evt.shiftKey);
     415
     416        if (e.target !== this.stage) {
     417            return;
     418        }
     419
     420        e.evt.preventDefault();
     421        this.x1 = this.stage.getRelativePointerPosition().x;
     422        this.y1 = this.stage.getRelativePointerPosition().y;
     423        this.x2 = this.stage.getRelativePointerPosition().x;
     424        this.y2 = this.stage.getRelativePointerPosition().y;
     425
     426        this.selectionRectangle.width(0);
     427        this.selectionRectangle.height(0);
     428        this.selecting = true;
     429    }
     430
     431    handleMouseMove(e) {
     432        if (!this.selecting) {
     433            return;
     434        }
     435        e.evt.preventDefault();
     436        this.x2 = this.stage.getRelativePointerPosition().x;
     437        this.y2 = this.stage.getRelativePointerPosition().y;
     438
     439        this.selectionRectangle.setAttrs({
     440            visible: true,
     441            x: Math.min(this.x1, this.x2),
     442            y: Math.min(this.y1, this.y2),
     443            width: Math.abs(this.x2 - this.x1),
     444            height: Math.abs(this.y2 - this.y1),
     445        });
     446    }
     447
     448    handleMouseUp(e) {
     449        this.selecting = false;
     450        this.stage.draggable(false);
     451
     452        if (!this.selectionRectangle.visible()) {
     453            return;
     454        }
     455
     456        e.evt.preventDefault();
     457        this.selectionRectangle.visible(false);
     458        const shapes = this.stage.find(".mapObj");
     459        const box = this.selectionRectangle.getClientRect();
     460        const selected = shapes.filter((shape) => Konva.Util.haveIntersection(box, shape.getClientRect()));
     461        this.mainTransformer.nodes(selected);
     462        console.log(this.mainTransformer.nodes());
     463    }
     464
     465    saveShapeDetails() {
     466        // this.shapes.forEach(shape => {
     467        //     shape.saveShapeDetails();
     468        //     console.log(shape.info);
     469        // });
     470        ShapeRegistry.saveDetails();
     471        console.log("thisflornum",this.floorNum)
     472        return  {
     473            shapes: ShapeRegistry.getShapes(this.floorNum),
     474            roomTypes: JSON.stringify(this.roomTypes),
     475            mapName: this.mapName,
     476            floorNum: this.floorNum
     477        }
     478    }
     479
     480    getPayload(){
     481        this.saveShapeDetails();
    144482        return {
    145           x: nextX,
    146           y: oldPos.y,
    147         };
    148       } else if (!snapToX && snapToY) {
    149         return {
    150           x: oldPos.x,
    151           y: nextY,
    152         };
    153       } else if (snapToX && snapToY) {
    154         return {
    155           x: nextX,
    156           y: nextY,
    157         };
    158       }
    159 
    160       return newPos;
    161     };
    162   }
    163 
    164   handleResize() {
    165     this.stage.width(this.container.offsetWidth);
    166     this.stage.height(this.container.offsetHeight);
    167     this.drawGrid();
    168   }
    169 
    170   zoom(e) {
    171    zoomStage(e,this.stage);
    172    this.drawGrid();
    173   }
    174 
    175   drawGrid() {
    176     this.gridLayer.destroyChildren();
    177 
    178     let width = this.stage.width();
    179     let height = this.stage.height();
    180 
    181     //presmetka od globalen koordinaten sistem vo lokalen na canvasot
    182     let transform = this.stage.getAbsoluteTransform().copy().invert();
    183     let topLeft = transform.point({
    184       x: 0,
    185       y: 0,
    186     });
    187 
    188     let bottomRight = transform.point({
    189       x: width,
    190       y: height,
    191     });
    192 
    193     let startX = Math.floor(topLeft.x / this.blockSize) * this.blockSize;
    194     let startY = Math.floor(topLeft.y / this.blockSize) * this.blockSize;
    195 
    196     let endX = Math.ceil(bottomRight.x / this.blockSize) * this.blockSize;
    197     let endY = Math.ceil(bottomRight.y / this.blockSize) * this.blockSize;
    198 
    199     for (let x = startX; x <= endX; x += this.blockSize) {
    200       let line = this.gridLine.clone({
    201         points: [x + 0.5, topLeft.y - this.blockSize, x + 0.5, bottomRight.y + this.blockSize],
    202       });
    203 
    204       line.transformsEnabled("position");
    205       line.perfectDrawEnabled(false);
    206       line.shadowForStrokeEnabled(false);
    207 
    208       this.gridLayer.add(line);
    209     }
    210 
    211     for (let y = startY; y <= endY; y += this.blockSize) {
    212       let line = this.gridLine.clone({
    213         points: [topLeft.x - this.blockSize, y + 0.5, bottomRight.x + this.blockSize, y + 0.5],
    214       });
    215 
    216       line.perfectDrawEnabled(false);
    217       line.shadowForStrokeEnabled(false);
    218       line.transformsEnabled("position");
    219       this.gridLayer.add(line);
    220     }
    221 
    222     this.mainLayer.moveToTop();
    223     this.infoPinLayer.moveToTop();
    224 
    225     this.gridLayer.batchDraw();
    226   }
    227 
    228   placeInfoPin(e) {
    229     e.evt.preventDefault();
    230     let mousePos = this.stage.getRelativePointerPosition();
    231     let infoPin = Factory.createShape("InfoPin", mousePos, this.blockSize, this.mainLayer, 0,1,1,true);
    232     this.addModalHandling(infoPin);
    233     this.shapes.push(infoPin);
    234     this.mainLayer.add(infoPin)
    235     infoPin.displayName(this.textLayer);
    236     console.log(infoPin.name());
    237   }
    238 
    239   toggleEfficientDrawingMode(e) {
    240     if (e.key === "e" || e.key === "E") {
    241       this.efficientDrawingMode = !this.efficientDrawingMode;
    242       console.log("EFFICIENT DRAWING MODE is: ", this.efficientDrawingMode);
    243 
    244       if (!this.efficientDrawingMode) {
    245         this.stopDrawing();
    246       }
    247     }
    248   }
    249 
    250   placeShape() {
    251     const mousePos = this.stage.getRelativePointerPosition();
    252     const placedObj = Factory.createShape(
    253       this.hoverObj.type,
    254       mousePos,
    255       this.blockSize,
    256       this.mainLayer,
    257       this.hoverObj.rotation(),
    258         1,
    259         1,
    260         true
    261     );
    262 
    263     if (!placedObj) return;
    264 
    265     this.mainLayer.add(placedObj);
    266     this.shapes.push(placedObj);
    267     this.addModalHandling(placedObj);
    268     this.mainLayer.draw();
    269     placedObj.displayName(this.textLayer);
    270     placedObj.snapToGrid();
    271 
    272     if (!this.efficientDrawingMode) {
    273       this.stopDrawing();
    274     }
    275   }
    276 
    277   stopDrawing() {
    278     this.mainTransformer.nodes([]);
    279     this.hoverObj.remove();
    280     this.dragLayer.removeChildren();
    281     this.stage.off("mousemove", this.boundMouseMoveHandler);
    282     this.stage.off("click", this.boundPlaceShapeHandler);
    283   }
    284 
    285   mouseMoveHandler() {
    286     const mousePos = this.stage.getRelativePointerPosition();
    287     this.hoverObj.position({ x: mousePos.x, y: mousePos.y });
    288     this.hoverObj.visible(true);
    289   }
    290 
    291   startDrawing(shapeType) {
    292     let pos = { x: 0, y: 0 };
    293     this.hoverObj = Factory.createShape(shapeType, pos, this.blockSize, this.dragLayer, 0);
    294 
    295     this.hoverObj.visible(false);
    296     this.dragLayer.add(this.hoverObj);
    297     this.dragLayer.moveToTop();
    298     this.boundMouseMoveHandler = this.mouseMoveHandler.bind(this);
    299     this.boundPlaceShapeHandler = this.placeShape.bind(this);
    300 
    301     this.stage.on("mousemove", this.boundMouseMoveHandler);
    302     this.stage.on("click", this.boundPlaceShapeHandler);
    303   }
    304 
    305   selectShape(e) {
    306     if (e.target.tagName === "LI") {
    307       const shapeType = e.target.getAttribute("data-info");
    308       this.startDrawing(shapeType);
    309       this.mainTransformer.nodes([]);
    310     }
    311   }
    312 
    313   addModalHandling(shape) {
    314     shape.on("dblclick", () => {
    315       const eventName = shape.modalEventName;
    316       if (eventName) {
    317         const data = {
    318           room: shape,
    319           map: this,
    320         };
    321         const event = new CustomEvent(eventName, { detail: data });
    322         window.dispatchEvent(event);
    323       }
    324     });
    325   }
    326 
    327   rotateShapesBy90Deg(e) {
    328     if (e.key === "r" || e.key === "R") {
    329       if (this.hoverObj) {
    330         this.hoverObj.rotate(90);
    331       }
    332       this.mainTransformer.nodes().forEach((node) => {
    333         node.rotate(90);
    334       });
    335     }
    336   }
    337 
    338   handleDelete(e) {
    339     if (e.key === "Delete") {
    340       this.mainTransformer.nodes().forEach((node) => {
    341         node.remove();
    342         this.shapes.splice(this.shapes.indexOf(node), 1);
    343       });
    344       this.mainTransformer.nodes([]);
    345       this.mainLayer.batchDraw();
    346     }
    347   }
    348 
    349   handleExitSelection(e) {
    350     if (e.key === "Escape") {
    351       this.mainTransformer.nodes([]);
    352       this.stopDrawing();
    353     }
    354   }
    355 
    356   handleMouseDown(e) {
    357     this.stage.draggable(e.evt.shiftKey);
    358 
    359     if (e.target !== this.stage) {
    360       return;
    361     }
    362 
    363     e.evt.preventDefault();
    364     this.x1 = this.stage.getRelativePointerPosition().x;
    365     this.y1 = this.stage.getRelativePointerPosition().y;
    366     this.x2 = this.stage.getRelativePointerPosition().x;
    367     this.y2 = this.stage.getRelativePointerPosition().y;
    368 
    369     this.selectionRectangle.width(0);
    370     this.selectionRectangle.height(0);
    371     this.selecting = true;
    372   }
    373 
    374   handleMouseMove(e) {
    375     if (!this.selecting) {
    376       return;
    377     }
    378     e.evt.preventDefault();
    379     this.x2 = this.stage.getRelativePointerPosition().x;
    380     this.y2 = this.stage.getRelativePointerPosition().y;
    381 
    382     this.selectionRectangle.setAttrs({
    383       visible: true,
    384       x: Math.min(this.x1, this.x2),
    385       y: Math.min(this.y1, this.y2),
    386       width: Math.abs(this.x2 - this.x1),
    387       height: Math.abs(this.y2 - this.y1),
    388     });
    389   }
    390 
    391   handleMouseUp(e) {
    392     this.selecting = false;
    393     this.stage.draggable(false);
    394 
    395     if (!this.selectionRectangle.visible()) {
    396       return;
    397     }
    398 
    399     e.evt.preventDefault();
    400     this.selectionRectangle.visible(false);
    401     const shapes = this.stage.find(".mapObj");
    402     const box = this.selectionRectangle.getClientRect();
    403     const selected = shapes.filter((shape) => Konva.Util.haveIntersection(box, shape.getClientRect()));
    404     this.mainTransformer.nodes(selected);
    405     console.log(this.mainTransformer.nodes());
    406   }
    407 
    408   saveShapeDetails() {
    409     this.shapes.forEach((room) => {
    410       room.saveShapeDetails();
    411       console.log(room.info);
    412     });
    413   }
    414 
    415   async render() {
    416     this.saveShapeDetails();
    417     const httpService = new HttpService("http://localhost:8080/api/protected", true);
    418     try {
    419       const response = await httpService.post("/render", this.shapes);
    420       console.log(response);
    421     } catch (err) {
    422       console.log("ERROR --> Could not render map --->", err);
    423     }
    424   }
    425 
    426   async saveMap(mapName) {
    427     this.saveShapeDetails();
    428     const httpService = new HttpService("http://localhost:8080/api/protected/maps", true);
    429     try {
    430       const response = await httpService.put(`/save?mapName=${mapName}`, this.shapes);
    431       console.log(response, "resp in builder");
    432     } catch (err) {
    433       console.log("ERROR --> Could not Save map --->", err);
    434     }
    435   }
    436 
    437   handleStageClick(e) {
    438     if (this.selectionRectangle.visible()) {
    439       return;
    440     }
    441 
    442     if (e.target === this.stage) {
    443       this.mainTransformer.nodes([]);
    444       return;
    445     }
    446 
    447     if (!e.target.hasName("mapObj")) {
    448       return;
    449     }
    450 
    451     const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
    452     const isSelected = this.mainTransformer.nodes().indexOf(e.target) >= 0;
    453 
    454     if (!metaPressed && !isSelected) {
    455       this.mainTransformer.nodes([e.target]);
    456       console.log("Sel 1");
    457     } else if (metaPressed && isSelected) {
    458       const nodes = this.mainTransformer.nodes().slice();
    459       nodes.splice(nodes.indexOf(e.target), 1);
    460       this.mainTransformer.nodes(nodes);
    461     } else if (metaPressed && !isSelected) {
    462       const nodes = this.mainTransformer.nodes().concat([e.target]);
    463       this.mainTransformer.nodes(nodes);
    464     }
    465   }
    466 
    467   addRoomType(roomType) {
    468     this.roomTypes.push(roomType);
    469   }
    470 
    471   getRoomTypes() {
    472     return this.roomTypes;
    473   }
    474 
    475   getRooms() {
    476     return this.getShapeInfoByType("Room");
    477   }
    478 
    479   getPins() {
    480     return this.getShapeInfoByType("InfoPin");
    481   }
    482 
    483   getEntrances() {
    484     return this.getShapeInfoByType("Entrance");
    485   }
    486 
    487   getConnections() {
    488     const pins = this.getShapeInfoByType("InfoPin");
    489     const entrances = this.getShapeInfoByType("Entrance");
    490     return [...pins, ...entrances];
    491   }
    492 
    493   getShapeInfoByType(type) {
    494     return this.shapes.filter((shape) => shape.className === type).map((shape) => shape.info);
    495   }
    496 
    497   updateConnections() {
    498     console.log("Update");
    499 
    500     this.shapes.forEach((shape) => {
    501       if (shape.className === "InfoPin" || shape.className === "Entrance") {
    502         shape.info.selectedPins.forEach((connectedShapeName) => {
    503           const connectedShape = this.shapes.find((s) => s.info.name === connectedShapeName);
    504           if (
    505             connectedShape &&
    506             (connectedShape.className === "InfoPin" || connectedShape.className === "Entrance")
    507           ) {
    508             if (!connectedShape.info.selectedPins.includes(shape.info.name)) {
    509               connectedShape.info.selectedPins.push(shape.info.name);
    510             }
    511           }
    512         });
    513       }
    514     });
    515   }
    516 
    517   removeConnection(from, to) {
    518     this.shapes
    519       .filter((s) => s.info.name === from || s.info.name === to)
    520       .forEach((s) => {
    521         s.info.selectedPins = s.info.selectedPins.filter((pin) => pin !== from && pin !== to);
    522       });
    523     console.log("Remove");
    524   }
    525 
    526   updateRoomNames() {
    527     this.textLayer.removeChildren();
    528     this.shapes.forEach((shape) => {
    529       shape.displayName(this.textLayer);
    530     });
    531     this.textLayer.children.forEach((child) => console.log(child));
    532   }
    533 
    534   clearMap() {
    535     this.mainLayer.removeChildren();
    536     this.shapes = [];
    537     this.hoverObj = null;
    538   }
    539 
    540   deserializeMap(data) {
    541     console.log("DESERIALIZING: ", data);
    542     this.clearMap();
    543     let dsrData = JSON.parse(data);
    544     dsrData.forEach((child) => {
    545       const shape = JSON.parse(child);
    546       const loadedShape = Factory.createShape(
    547         shape.className,
    548         { x: shape.attrs.x, y: shape.attrs.y },
    549         this.blockSize,
    550         this.mainLayer,
    551         shape.attrs.rotation,
    552           shape.attrs.scaleX,
    553           shape.attrs.scaleY
    554       );
    555       loadedShape.loadInfo(shape.attrs);
    556       this.shapes.push(loadedShape);
    557       this.addModalHandling(loadedShape);
    558       this.mainLayer.add(loadedShape);
    559     });
    560     this.mainTransformer.nodes([]);
    561     this.mainLayer.add(this.mainTransformer);
    562     this.mainLayer.add(this.selectionRectangle);
    563 
    564     this.shapes.forEach((shape) => shape.displayName(this.textLayer));
    565   }
     483            shapes: ShapeRegistry.getShapes(this.floorNum),
     484            roomTypes: JSON.stringify(this.roomTypes),
     485            mapName: this.mapName,
     486            floorNum: this.floorNum
     487        }
     488    }
     489
     490
     491    handleStageClick(e) {
     492        if (this.selectionRectangle.visible()) {
     493            return;
     494        }
     495
     496        if (e.target === this.stage) {
     497            this.mainTransformer.nodes([]);
     498            return;
     499        }
     500
     501        if (!e.target.hasName("mapObj")) {
     502            return;
     503        }
     504
     505        const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
     506        const isSelected = this.mainTransformer.nodes().indexOf(e.target) >= 0;
     507
     508        if (!metaPressed && !isSelected) {
     509            this.mainTransformer.nodes([e.target]);
     510            console.log("Sel 1");
     511        } else if (metaPressed && isSelected) {
     512            const nodes = this.mainTransformer.nodes().slice();
     513            nodes.splice(nodes.indexOf(e.target), 1);
     514            this.mainTransformer.nodes(nodes);
     515        } else if (metaPressed && !isSelected) {
     516            const nodes = this.mainTransformer.nodes().concat([e.target]);
     517            this.mainTransformer.nodes(nodes);
     518        }
     519    }
     520
     521    addRoomType(type) {
     522        this.roomTypes.push(type);
     523    }
     524
     525    removeRoomType(targetType) {
     526        this.roomTypes = this.roomTypes.filter(type => type !== targetType);
     527    }
     528
     529    getRoomTypes() {
     530        return this.roomTypes;
     531    }
     532
     533    getRooms() {
     534        return this.getShapeInfoByType("Room");
     535    }
     536
     537    getPins() {
     538        return this.getShapeInfoByType("InfoPin");
     539    }
     540
     541    getEntrances() {
     542        return this.getShapeInfoByType("Entrance");
     543    }
     544
     545
     546
     547    getShapeInfoByType(type) {
     548        return ShapeRegistry.getShapes(this.floorNum).filter((shape) => shape.className === type).map((shape) => shape.info);
     549    }
     550
     551
     552    drawConnection(node1Name, node2Name) {
     553
     554        ShapeRegistry.drawConnection(node1Name,node2Name);
     555    }
     556
     557    getNodeByName(name) {
     558        return ShapeRegistry.getShapes(this.floorNum).filter(shape => shape instanceof MapNode && shape.info.name === name)[0];
     559    }
     560
     561    removeConnection(from, to) {
     562        ShapeRegistry.removeConnection(from,to);
     563    }
     564
     565    updateRoomNames() {
     566        this.textLayer.removeChildren();
     567        ShapeRegistry.getShapes(this.floorNum).forEach((shape) => {
     568            shape.displayName(this.textLayer);
     569        });
     570
     571    }
     572
     573    isMainEntranceSelected() {
     574        console.log(this.getEntrances().forEach((en) => console.log(en.isMainEntrance, "asdsad")));
     575
     576        let hasMainEntrance = false;
     577
     578        this.getEntrances().forEach((entrance) => {
     579            if (entrance.isMainEntrance === true) hasMainEntrance = true;
     580        });
     581
     582        return hasMainEntrance;
     583
     584    }
     585
     586    clearMap() {
     587        this.mainLayer.removeChildren();
     588        this.hoverObj = null;
     589    }
     590
     591
     592    // ova  klasa i map display da nasledbat od glavna klasa
     593
     594    loadNewFloor(floor) {
     595
     596        this._floorNum = floor?.num;
     597        let data = floor?.mapData;
     598
     599        if (data == null || data === "") return;
     600
     601        this.deserializeMap(data);
     602        shapeRegistry.getShapes(this.floorNum).forEach((shape) => {
     603            this.mainLayer.add(shape);
     604        });
     605
     606
     607    }
     608
     609    //nov
     610    deserializeMap(data) {
     611        console.log("DESERIALIZING: ", data);
     612        ShapeRegistry.clear(this.floorNum);
     613
     614        if (data != null) {
     615            const dsrData = JSON.parse(data);
     616            //load shapes
     617            dsrData.forEach((shape) => {
     618                const attrs = {
     619                    position: {x: shape.attrs.x, y: shape.attrs.y},
     620                    width: shape.attrs.width,
     621                    height: shape.attrs.height,
     622                    layer: this.mainLayer,
     623                    blockSize: this.blockSize,
     624                    rotation: shape.attrs.rotation,
     625                    scaleX: shape.attrs.scaleX,
     626                    scaleY: shape.attrs.scaleY,
     627                    increment: false,
     628                    snap: true,
     629                    fromLoad: true,
     630                    floorNum: this.floorNum
     631                };
     632
     633                const loadedShape = Factory.createShape(shape.className, attrs);
     634                loadedShape.loadInfo(shape.attrs);
     635                ShapeRegistry.add(loadedShape);
     636                // na destroy trebit events da sa trgnat
     637                addEventHandling(loadedShape, this, "dblclick");
     638            });
     639            let nodes = ShapeRegistry.getShapes(this.floorNum).filter((shape) => shape.className === "InfoPin" || shape.className === "Entrance" || shape.className === "Stairs");
     640            nodes.forEach((pin) => {
     641                let connectedPins = pin.info.selectedPins;
     642                if (connectedPins) {
     643                    connectedPins.forEach((slPin) => {
     644                        console.log("CONN node1: " + pin + "conn node2: " + slPin)
     645                        this.drawConnection(pin.info.name, slPin);
     646                    });
     647                }
     648            });
     649        }
     650
     651        this.mainTransformer.nodes([]);
     652        this.mainLayer.add(this.mainTransformer);
     653        this.mainLayer.add(this.selectionRectangle);
     654
     655        ShapeRegistry.getShapes(this.floorNum).forEach((shape) => shape.displayName(this.textLayer));
     656    }
     657
    566658}
Note: See TracChangeset for help on using the changeset viewer.