23 May

Doing some cool stuff with JavaScript in Bluebeam (Part 2)

In part 1 we added a single line of JavaScript, it was basic. But hopefully that single line of JavaScript provided some inspiration on how you could make other stamps you might create dynamic, and less specific.

In this post we’ll do another example, but this time I’ll show you how to use some data input by the user when you place a stamp to do some calculations using JavaScript.

Example 2 – Calculating bracing capacity for Gib walls with a Bluebeam stamp

In New Zealand in residential timber framed houses we brace them typically using gypsum board linings. The bracing capacity achieved is typically based on testing and documented as the number of Bracing Units (BU’s) that can be taken by a given wall type/construction based on a given performance objective. The test is called the P21 test which quantifies the bracing achieved.

The suppliers of these products publish these capacities so we as Engineers can use them. We use these capacities to design the lateral bracing systems more efficiently in houses, profit!

Sometimes Architects give it a go also, fixing this means minus profit!

Without the engineering knowledge when architects think they can do engineering, it’s a mixed bag to see what they interpret the requirements to be. They just don’t read code clauses the same way we do.

20 BU’s is defined as 1kN. A wall type with 100 BU/m capacity has effectively 5kN/m shear capacity. Wall capacities are based on standard 2.4m height walls. Higher walls are downrated accordingly, shorter walls are taken to have the same capacity as a 2.4m high wall.

We have non-specific engineering design codes that give you the total bracing demand for Wind and Earthquakes for a given type of house/location/claddings, etc. It’s up to the engineer and sometimes the architect to provide sufficient bracing capacity and satisfy the rules around distribution of these bracing elements. Follow the rules and the intent is your house doesn’t fall down under a code level wind or seismic event.

What we’ll demonstrate here is a stamp utilising some simple JavaScript code that allows you to calculate the Wind (W) and Earthquake (EQ) capacity for a given wall length, wall height, and lining type using the capacity data provided by a manufacturer. In this example we’ll use Gib systems published capacities, they are probably the most widely specified system in NZ.

The Bracing Unit concept isn’t limited to gypsum-based linings, it can equally apply to plywood shear walls, proprietary steel bracing frames. If you can put it through the P21 test, you can establish the BU’s capacity. The BU capacity establishes a similar level of performance irrespective of the type of system.

I find this stamp useful during the concept stage of a project but can also be used to document the final capacities achieved. Rather than running off to the manufacturers data and grabbing my calculator every time, simply dump the stamp on a PDF of the plan and enter the wall length, wall height as measured in Bluebeam. The embedded JavaScript code then completes a calculation and pops the results into the textboxes in the stamp. Neat!

A few temporary fields on the left for storing temporary calculation, and the stamp on the right

Most of the textboxes have a little code associated with them, we’ll go through that in a bit to give you a flavour for things. But place the stamp and you’re presented with a few input windows for the bracing element length, height, and type.

The result with the correct number of calculated BU’s is shown below, the W & EQ cells are the result of the calculation process we’ll code below.

The code

Look at the following image, we’ll name our form textbox regions as follows: –

It’s also of importance to recognise that there is sometimes an order to the code running that goes in order of the forms. Make sure you arrange as follows or rearrange until it works. Basically, I don’t f&*king know because Bluebeam doesn’t have an API for this shit.

This is the way you drive what code runs first and in what order. This is important if a subsequent calculation is driven by a previous answer. For example, you cannot calculate the number of BU’s until you know the length, height, and wall type which are driven by user inputs.

Let’s look at what code we need to put in place to getting this working. Don’t judge my JavaScript….

‘L’ code

event.value = (Math.round(app.response("Bracing Element Length")*100)/100).toFixed(2)

Here we are getting the users value for the bracing panel length and doing some roundy stuff, so we only display two fixed decimal places.

‘TYPE’ code

event.value = app.response("Bracing Element Type \n \nGIB Standard Bracing Systems \n \n1 = GS1-N \n2 = GS2-N \n3 = GS2-NOM \n4 = GSP-H \n \nGIB Braceline Bracing Systems \n \n5 = BL1-H \n6 = BLG-H \n7 = BLP-H \n \nECOPLY Barrier Bracing Systems \n \n8 = EPB1 \n9 = EP2 \n10 = EPBS \n11 = EPBG \n")
//Updated & checked May 2020
var temp
var max_bracing
//max bracing units per meter (150 for concrete and 120 for timber)
max_bracing = this.getField("max_limit").value

if (event.value == 1) {
    temp = "GS1-N"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 70
        this.getField("EQ_temp").value = 60
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 50
        this.getField("EQ_temp").value = 55
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 2) {
    temp = "GS2-N"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 95
        this.getField("EQ_temp").value = 85
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 70
        this.getField("EQ_temp").value = 65
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 3) {
    temp = "GS2-NOM"
    if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 50
        this.getField("EQ_temp").value = 50
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 4) {
    temp = "GSP-H"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 150
        this.getField("EQ_temp").value = 150
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 100
        this.getField("EQ_temp").value = 115
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 5) {
    temp = "BL1-H"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 125
        this.getField("EQ_temp").value = 105
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 90
        this.getField("EQ_temp").value = 100
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 6) {
    temp = "BLG-H"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 150
        this.getField("EQ_temp").value = 145
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 110
        this.getField("EQ_temp").value = 115
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 7) {
    temp = "BLP-H"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 150
        this.getField("EQ_temp").value = 150
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 120
        this.getField("EQ_temp").value = 135
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 8) {
    temp = "EPB1"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 120
        this.getField("EQ_temp").value = 135
    } else if (this.getField("L").value >= 0.6) {
        this.getField("W_temp").value = 95
        this.getField("EQ_temp").value = 105
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 80
        this.getField("EQ_temp").value = 95
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 9) {
    temp = "EP2"
    if (this.getField("L").value >= 0.6) {
        this.getField("W_temp").value = 105
        this.getField("EQ_temp").value = 115
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 10) {
    temp = "EPBS"
    if (this.getField("L").value >= 2.4) {
        this.getField("W_temp").value = 80
        this.getField("EQ_temp").value = 90
    } else if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 65
        this.getField("EQ_temp").value = 70
    } else if (this.getField("L").value >= 0.6) {
        this.getField("W_temp").value = 60
        this.getField("EQ_temp").value = 65
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 60
        this.getField("EQ_temp").value = 60
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}

if (event.value == 11) {
    temp = "EPBG"
    if (this.getField("L").value >= 1.2) {
        this.getField("W_temp").value = 150
        this.getField("EQ_temp").value = 150
    } else if (this.getField("L").value >= 0.4) {
        this.getField("W_temp").value = 100
        this.getField("EQ_temp").value = 115
    } else {
        this.getField("W_temp").value = 0
        this.getField("EQ_temp").value = 0
    }
}
event.value = temp

Here we are getting the system type, and then establishing the BU’s per metre from suppliers’ tables like shown below. The code writes these values to some temporary textboxes so we can utilise these values for later calculations. Additionally, I forgot that I also had all the Ecoply values in there… Bonus for you.

‘HT’ code

event.value = (Math.round(app.response("Bracing Element Height")*100)/100).toFixed(2)

Same as ‘L’ really but for height.

‘W_temp’ & ‘EQ_temp’ code

Nothing to see here, no code required. These just temporarily store the BU’s per metre values from the ‘TYPE‘ code.

‘EQ’ code

event.value = Math.round(Math.min(max_bracing, this.getField("EQ_temp").value * Math.min(1, 2.4 / this.getField("HT").value)) * this.getField("L").value) + " BU";

if (this.getField("EQ_temp").value * Math.min(1, 2.4 / this.getField("HT").value) <= max_bracing) {
    event.value = event.value
} else {
    event.value = event.value + "*"
};

Here we are finally working out the capacity and checking it against the maximum value we have stored in the ‘max_limit‘ textbox. Basically, I just have two stamps, one for concrete floors, and one for timber floors with the different limits hard coded in there.

‘W’ code

event.value = Math.round(Math.min(max_bracing, this.getField("W_temp").value * Math.min(1, 2.4 / this.getField("HT").value)) * this.getField("L").value) + " BU"

if (this.getField("W_temp").value * Math.min(1, 2.4 / this.getField("HT").value) <= max_bracing) {
    event.value = event.value
} else {
    event.value = event.value + "*"
};

Rinse and repeat of ‘EQ‘ code.

‘EQ_limit’ code

if (this.getField("EQ_temp").value * Math.min(1, 2.4 / this.getField("HT").value) <= max_bracing) {
    event.value = " "
} else {
    event.value = "*" + max_bracing + " BU/m LIMIT"
};

This is a warning that we’ve been limited by the maximum BU per metre limit.

‘W_limit’ code

if (this.getField("W_temp").value * Math.min(1, 2.4 / this.getField("HT").value) <= max_bracing) {
    event.value = " "
} else {
    event.value = "*" + max_bracing + " BU/m LIMIT"
};

Rinse and repeat of ‘EQ_limit‘ code.

‘max_limit’ code

Manually fill out the textbox with the upper limit. As noted above make a stamp for timber floors and concrete floors using 120, and 150 respectively.

Conclusion

If you’ve followed along and I have not lost you, then you have your second dynamic stamp or at the very least I haven’t wasted my time and you can use similar concepts to create something completely different but unique to the way you work.

Your imagination is the limit. Do some design, like work out preliminary strength or deflection checks without breaking out your calculator…. profit!

Now if you were able to draw a dimension in conjunction with a stamp and use that dimension seamlessly in a calculation ….. oh, wait this is Bluebeam, we wouldn’t want the developers to make it insanely useful out of the box…. too sarcastic? Too bad…

PS….

I wish I had done this when I first wrote the code, I struggled with Bluebeam’s lacklustre editor and the JavaScript formatting. So just copy it into your favourite code editor and use the automatic formatting tools in there to make sure your code is formatted correctly. I use VS Code now. Trust me, if you are not familiar with JavaScript, this will help a lot to get the formatting nomenclature right. Because get it wrong and Bluebeam doesn’t tell you why…. aarrrghhh……..

Leave a Reply

Your email address will not be published. Required fields are marked *