Trivium
Trivium

Reputation: 1

Importing JavaScript Class causing and Uncaught Reference Error

I'm coding a few JavaScript classes for my school project and need to make some circuit breaker components. I'm following the standard for importing and exporting JavaScript classes, but when I test the code using XAMPP and the website being built for these JavaScript classes, I'm getting this error "CircuitBreaker.js:12 Uncaught ReferenceError: Cannot access 'Component' before initialization at CircuitBreaker.js:12:37"

Here are the Classes Connected to this Component.

Component.js

import {Drag_Event, Zoom_Event} from "./CADDIEngine.js";

export class Component {
    constructor(name, color="black", iconPath=null) {
        // Functionality 
        this.children = [];
        this.current_rating = 0         // component current rating
        this.errors = [];
        this.frequency = 0;             // if Component has a frequency rating it should be 60hz
        this.id = 0;                    // RBDC team will implement a UUID system later
        this.icon_path = " ";                // this should be a hard coded path using in the 
                                        //    child class contructor
        this.name = name;
        this.parent = null;             // start the parent as null
        this.pass_up_map = {};          // Used for passing information up & down the tree
        this.personal_current_draw = 1; // This will not be used for most components
        this.phase = 0;                 // 1 = single-phase, 3 = three-phase, 0 = N/A
        this.sccr = 0;                  // "short circuit current rating"
        this.type_array = [];           // list of function types component fulfils
        this.volt_rating = {            //Component voltage rating range
          min: 0,
          max: 0
        };
        this.waveForm = 0;              // AC or DC (1 = AC, 2 = DC, 0 = N/A)

        // Attributes for the GUI interface.
        // These keep track of coordinate information
        // The RBDC team should be the only people using
        // or modifying these variables

        // Coordinate and location attributes
        this.absX = 200;
        this.absY = 200;
        this.relativeX = this.absX;
        this.relativeY = this.absY;
        this.offsetX = 0; // offset based on user position
        this.offsetY = 0; // offset based on user position

        // Location attributes for the middle
        this.absMiddleX = this.absX + (this.width / 2);
        this.absMiddleY = this.absY + (this.height / 2);
        this.relativeMiddleX = this.relativeX + (this.width / 2);
        this.relativeMiddleY = this.relativeY + (this.height / 2);

        // Configures image

        if (iconPath == null){            
            iconPath = "../assets/component_icons/icon_missing.svg";
        }

        this.hasIcon = false;
        this.img;
        if (iconPath != null){
            this.hasIcon = true;
            this.img = new Image();
            this.img.src = iconPath;
        }


        // Misc attributes
        this.width = 80;
        this.height = 80;
        this.stacking_height = this.height * 1.5; // Defines how much space this components wants between it and its children
        this.color = color;
        this.canvasContext;
        this.selected = false;
        this.engine;


        // Call the first update
        this._update_middle_coords();
        
    }

    drag(deltaX, deltaY){
        this.relativeX += deltaX;
        this.relativeY += deltaY;

        this._update_middle_coords();
        
    }

    set_coords(newX=this.absX, newY=this.absY){
        // // Calculate how far off the relative Coordinates are so we can account for them
        // let relativeOffsetX = this.absX - this.relativeX; 
        // let relativeOffsetY = this.absY - this.relativeY; 

        
        let relativeOffsetX =  this.relativeX - this.absX; 
        let relativeOffsetY =  this.relativeY - this.absY; 

        // Update the absolute coords
        this.absX = newX;
        this.absY = newY;

        // Update relative coords with new abs coords and relativeOffset
        this.relativeX = this.absX + relativeOffsetX;
        this.relativeY = this.absY + relativeOffsetY;

        // Reset relativeX, relativeY, then  apply all the events from engine
        // this.absX = newX;
        // this.absY = newY;

        // this.relativeX = this.absX;
        // this.relativeY = this.absY;

        // if (this.engine != null){
        //     // Apply all the apst movement events
        //     console.log("Applying everything to " , this.name);
        //     console.log(this.engine);
        //     for (let movement of this.engine.movement_record){

        //         if (movement instanceof Drag_Event){
        //             // this.drag(movement.totalMoveX, movement.totalMoveY);
        //         } else if (movement instanceof Zoom_Event){
        //             this.change_zoom(movement.curMouseX, movement.curMouseY, movement.scaleDelta, movement.scale);
        //         }

        //     }
        // }


        // Make middle coords update
        this._update_middle_coords();
    }

    update_tree(){

        // Finds the top most parent
        if (this.parent == null){
            // this is the parent. Start recursing all the way down.
            this._update_recursive_down();

        } else {
            // this is not the grandparent. 
            this.parent.update_tree();
        }

        this.organize_children();
    }

    click(){
        console.log("" , this.name, " Component click");

        if (this.selected){
            this.selected = false;
        } else {
            this.selected = true;
        }
    }

    deselect(clientX, clientY){

        /*

            Deselects the Component. This primarily
            acts as an interface for child classes.

        */

        this.selected = false;
    }

    _update_recursive_down(){

        // this.total_current_draw = this.personal_current_draw;

        // Gets pass_up_map
        this.pass_up_map['total_current_draw'] = this.personal_current_draw;
        this.pass_up_map['widest_root'] = 0;
        this.pass_up_map['longest_root'] = 0;

        // Null map to hold data when looping
        let this_child_map = {};

        for (let child of this.children) {

            // Send update down & get updated result
            this_child_map = child._update_recursive_down();

            // Updates total current draw
            this.pass_up_map['total_current_draw'] += this_child_map['total_current_draw'];

            // Updates the widest root
            this.pass_up_map['widest_root'] += (this_child_map['widest_root'] - 1) <= 0 ? 0 : this_child_map['widest_root'] - 1; // ternary makes sure it isn't below 0
            this.pass_up_map['widest_root'] += 1; // increment for this child

            // Updates the deepest root

            if (this_child_map['longest_root'] + 1 > this.pass_up_map['longest_root']){
                this.pass_up_map['longest_root'] = this_child_map['longest_root'] + 1;
            }

        }

        // Add self to the longest_root value
        // this.pass_up_map['longest_root']++;

        this.update_self();
        // return this.total_current_draw;
        return this.pass_up_map;
    }

    organize_children(){
        let thisMaxRoot = this.pass_up_map['widest_root'];

        // Verifies that the max root is not 0
        // This can happen to components without descendants
        // since those components interpret no descendants as 
        // 0 wide
        if (thisMaxRoot < 1){
            thisMaxRoot = 1;
        }


        // Variables that control positioning of component children
        let childWidth = 100;
        let childGap = 70;
        let totalChildWidth = childWidth + childGap + 100;
        let leftOffset = (childWidth * thisMaxRoot) / 2;
        
        // Variables for the loop
        let thisChildIndex = 0;
        let childMaxRoot;
        let childAbsX;


        // Organizes the children
        if (this.children.length == 1){
            // There shouldn't be any offset if there's only one child. 
            // Thus, this is a special case for that

            let thisChild = this.children[0];

            // Calculates the offset to make sure it is centered on x axis

            thisChild.set_coords(this.absX, this.absY + this.stacking_height); 
            thisChild.organize_children();

        } else if (this.children.length > 1) {

            // Since there is more than one child we need to do this loop
            for (var child of this.children){

                // Gets the wideness of this child
                childMaxRoot = child.pass_up_map['widest_root'];
                
                // Calculates the new absolute coordinates and sets them
                childAbsX =  this.absX - leftOffset + (thisChildIndex * totalChildWidth);
                child.set_coords(childAbsX, this.absY + this.stacking_height);

                // Update the index in regards to the total length of this child
                thisChildIndex += (childMaxRoot > 0) ? childMaxRoot : 1;

                // Recurse
                child.organize_children();

            }
        }
    }

    change_zoom(mouseX, mouseY, scaleDelta, scale){
        this.offsetX -= (this.relativeMiddleX - mouseX) * scaleDelta ;
        this.offsetY -= (this.relativeMiddleY - mouseY) * scaleDelta ;

        // this.engine.scale = scale;
        
        this._update_middle_coords();
    }

    _update_middle_coords(){   
        this.absMiddleX = this.absX + (this.width / 2);
        this.absMiddleY = this.absY + (this.height / 2);


        // Make sure we aren't multiplying by undefined. If engine isn't 
        // set yet then just use 1 as our multiplyer
        let this_scale;
        if (typeof this.engine != 'undefined') {
            this_scale = this.engine.scale;
        } else {
            this_scale = 1;
        }

        this.relativeMiddleX = this.relativeX + (this.width / 2) * this_scale;
        this.relativeMiddleY = this.relativeY + (this.height / 2) * this_scale;

    }

    draw(canvasContext, scale){
        let thisFrameX = this.relativeX + this.offsetX;
        let thisFrameY = this.relativeY + this.offsetY;
        let thisFrameMidX = this.relativeMiddleX + this.offsetX;
        let thisFrameMidY = this.relativeMiddleY + this.offsetY;
        let thisFrameWidth = this.width;
        let thisFrameHeight = this.height;
        
        // Always restart the path before drawing
        canvasContext.beginPath();

        if (this.hasIcon){
            canvasContext.drawImage(this.img, thisFrameX, thisFrameY, thisFrameWidth * scale, thisFrameHeight * scale);
        } else {
            // set color
            canvasContext.fillStyle = this.color;

            // Draw the rectangle, as well as a red dot to indicate the center
            canvasContext.fillRect(thisFrameX, thisFrameY, thisFrameWidth * scale, thisFrameHeight * scale);
        }

        
    
        if (this.selected){
            canvasContext.strokeStyle = "white";
            canvasContext.strokeRect(thisFrameX, thisFrameY, thisFrameWidth * scale, thisFrameHeight * scale);
        }

        canvasContext.arc(thisFrameMidX, thisFrameMidY, 1, 0, 2 * Math.PI, false);
        canvasContext.fillStyle = "red";
        canvasContext.fill();
        canvasContext.fillStyle = "black";

        // Draws line to the parent
        if (this.parent != null){
            // Update parents middle coords 
            this.parent._update_middle_coords();

            canvasContext.strokeStyle = "black";
            canvasContext.lineWidth = 2;
            canvasContext.beginPath();
            canvasContext.moveTo(this.relativeMiddleX + this.offsetX, this.relativeY + this.offsetY);
            canvasContext.lineTo(this.parent.relativeMiddleX + this.parent.offsetX, this.parent.relativeY + (this.parent.height * this.parent.engine.scale) + this.parent.offsetY);
            canvasContext.stroke();
        }
        
    }
  
    update_self() {
      // must be implemented by child classes
      //   throw new Error("update_self() must be implemented by child classes");
    }
  
    update_server() {
        // to be implemented by RBDC
        // This will send updated data back to the server for storage
        return false;
    }
  
    add_child(newComponent, perpetuate=true) {
        // Adds a child to the component
        // This will be used by the frontend to connect components together

        this.children.push(newComponent);
        if (perpetuate){
            newComponent.set_parent(this, false);
        }

        // Make sure everything updates to prevent visual bugs
        this.update_tree();
        this.organize_children();
    }
  
    set_parent(newComponent, perpetuate=true) {
        // Adds a parent to the component
        // This will be used by the frontend to connect components together

        this.parent = newComponent
        if (perpetuate){
            newComponent.add_child(this, false);
        }

        // Make sure everything updates to prevent visual bugs
        this.update_tree();
        this.organize_children();
    }

    get_data(){
        // Get ID of all children
        let childIDArr = [];
        for (let child in this.children){
            childIDArr.push(child.id);
        }

        // Get the ID of parent, or use null if this is a top parent
        let parentId = null;
        if (this.parent != null){
            parentId = this.parent.id;
        }

        return {
            id: this.id,
            errors: this.errors,
            children: childIDArr,
            parent: parentId,
            personal_current: this.personal_current_draw,
            total_current: this.total_current_draw
        }
    }
  
    get_errors() {
      return this.errors;
    }

    get_total_current_draw() {
        return this.total_current_draw;
    }

    get_personal_current_draw() {
        return this.personal_current_draw;
    }

    get_children() {
        return this.children;
    }

    get_parent() {
        return this.parent;
    }
}
  

CircuitBreaker.js

import { Component } from "./Component.js";

export class CircuitBreaker extends Component {
  constructor (children, current_rating, errors, id, icon_path, name, parent, pass_up_map,
    phase, sccr, type_array, waveform, volt_rating) {
      //this.CircuitBreaker = new Component();
      // passing in parent class
      super(children, current_rating, errors, id, icon_path, name, parent, pass_up_map,
        phase, sccr, type_array, waveform, volt_rating);
      
      // constructing Circuit Breaker specific properties
      this.name = "Circuit Breaker";
      this.triptype = "";
      this.protection_multiplier = 0.0;
  }

InstantMCCB.js

import { CircuitBreaker } from "./CircuitBreaker.js";

export class InstantMCCB extends CircuitBreaker {
    constructor (children, current_rating, errors, id, icon_path, name, parent, pass_up_map,
        phase, sccr, type_array, waveform, volt_rating) {
          // passing in parent class
          super(children, current_rating, errors, id, icon_path, name, parent, pass_up_map,
            phase, sccr, type_array, waveform, volt_rating);
          
          // constructing Instant MCCB Circuit Breaker specific properties
          this.name = "InstantMCCB";
          this.triptype = "InstantMCCB";
          this.protection_multiplier = 8.0;
    }

// Methods

    // validates the UL 508A rules for Instant MCCB Circuit Breakers
    update_self() {
        i = 0;
        while (this.children[i] != 'null') {
            i++;
            if (this.children[i] == 'null') {
                fulloadamps = this.children[i].Load.getFullLoadAmps();
            }
        }
        if (fulloadamps < (current_rating * 0.8)) {
            this.errors = "Full Load Current of Load is to low";
        } else if ( fullloadamps < (this.volt_rating['max'] * this.protection_multiplier)) {
            this.errors = "% Branch Circuit Protection Multiplier is to low"
        } else {
            return true;
        }
    }
    
    // creates a JSON array for the interfaces of the UI and the database.
    get_data() {
        JSON_InstantMCCB = JSON.stringify(this)
        return JSON_InstantMCCB;
    }
    
    // takes in a JSON array to set the Instant MCCB Circuit Breaker attributes
    set_data() {
        return 0;
    }
}

Obviously The Code isnt finished for most of these classes, but I am unable to even start bug testing the code since I am unable to initlaize these functions even though I can initilaze Add_Component.js and Component.js which are using the same important and export code.

I'm currently Using CADDIEEngine to add the Components to the GUI another class member is building for the project, and I am unable to get the website to add any of the other Components built besides Add_Component and Component.

CADDIEEngine.js

import { Add_Component } from "./Add_Component.js";
import { Component } from "./Component.js";
import { CircuitBreaker } from "./CircuitBreaker.js";
import { InstantMCCB } from "./InstantMCCB.js";
import { InverseMCCB } from "./InverseMCCB.js";
import { MPCB } from "./MPCB.js";

export class CADDIEngine {

    // CAD Drafting Interface Engine (CADDIE)
    // CAD Design and Display Interface ENgine

    constructor (targetFPS) {

        // Set up canvas
        this.canvas = document.querySelector('.test-canvas');
        this.c = this.canvas.getContext('2d');
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;

        // Set up mouse tracking attributes
        this.middleClickPressed = false;
        this.curMouseX = 0;
        this.curMouseY = 0;
        this.lastMouseX = 0;
        this.lastMouseY = 0;
        this.mouseDX = 0;
        this.mouseDY = 0;

        // Performance attributes
        this.rollingFPS = 0;
        this.fps_target = targetFPS;
        this.fps = 0;

        // Zooming attributes        
        this.scale = 1;
        this.zoomOffsetX = 1;
        this.zoomOffsetY = 1;   
        this.mouseLastZoomX = 0;   
        this.mouseLastZoomY = 0;
        this.pauseForScroll = false;

        // Miscellenious attributes
        this.components = [];    
        this.pushed_buttons = {};  
        this.movement_record = [];
        this.supported_components = { // List of supported components
            "Add Button": Add_Component,
            "Generic Component": Component,
            "Instant MCCB": InstantMCCB,
            "Inverse MCCB": InverseMCCB,
            "MPCB": MPCB,
            // "Ad Button": Add_Component, // extra bogus components to demo the interface
            // "Geeric Componnt": Component,
            // "Add utton": Add_Component,
            // "Generic Coponent": Component,
            // "Add Butto": Add_Component,
            // "Generic Cmponent": Component,
            // "Add utton": Add_Component,
            // "Generic Cmponent": Component,
            // "Ad Button": Add_Component,
            // "Generic Coponent": Component,
            // "Add Buon": Add_Component,
            // "Genericomponent": Component,
        };

I've tried Commenting out all the code currently in the classes besides the constructor and super functions, making all the exports a default export, and tried initializing the Component class before the CircuitBreaker class is initialized with a

let Component = new Component("CircuitBreaker");

or

const Component = new Component("CircuitBreaker");

I'm not sure what exactly is causing the unexplained reference error where Component is not intialized before CircuitBreaker that is not an issue with the Component and Add_Component classes.

Upvotes: 0

Views: 76

Answers (0)

Related Questions