The Conduit and Wire Weight Calculator assists in planning electrical conduit runs by calculating total weights, determining fill percentages, checking ampacity and grounding requirements, and exporting data to PDF.
index.html: The main HTML file that includes the structure of the calculator, forms, and buttons.
Handles adding conduits and wires to the entry list.
Function: Adds a conduit entry to the list.
const isFreeAir = document.getElementById('freeAir').checked;freeAir)
const conduitType = document.getElementById('conduitType1').value;
const conduitSize = document.getElementById('conduitSize1').value;
const conduitLength = document.getElementById('conduitLength1').value;
conduitType1, conduitSize1, and conduitLength1)
const listItem = document.createElement('li');
if (isFreeAir) {
listItem.innerHTML = `Conduit: Type - Free Air `;
} else {
listItem.innerHTML = `Conduit: Type - ${conduitType}, Size - ${conduitSize}, Length - ${conduitLength} ft `;
}
document.getElementById('entryList').appendChild(listItem);entryList)
document.getElementById('conduitType1').selectedIndex = 0;
document.getElementById('conduitSize1').selectedIndex = 0;
document.getElementById('conduitLength1').value = '10';
document.getElementById('freeAir').checked = false;
toggleFreeAir();
conduitType1, conduitSize1, conduitLength1, and freeAir)updateTotalWeightAndWireFill();
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Function: Adds a wire entry to the list.
const wireType = document.getElementById('wireType1').value;
const wireSize = document.getElementById('wireSize1').value;
const wireLength = document.getElementById('wireLength1').value;
const wireCount = document.getElementById('wireCount1').value;
wireType1, wireSize1, wireLength1, and wireCount1)
const listItem = document.createElement('li');
listItem.innerHTML = `Wire: Type - ${wireType}, Size - ${wireSize}, Length - ${wireLength} ft, Count - ${wireCount} `;
document.getElementById('entryList').appendChild(listItem);entryList)
document.getElementById('wireType1').selectedIndex = 0;
document.getElementById('wireSize1').selectedIndex = 0;
document.getElementById('wireLength1').value = '10';
document.getElementById('wireCount1').value = '1';
wireType1, wireSize1, wireLength1, and wireCount1)updateTotalWeightAndWireFill();
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Similar to addWire(), but specifically for non-CCC wires.
Similar to addWire(), but specifically for EGC wires.
Similar to addWire(), but specifically for GEC wires.
Similar to addWire(), but specifically for SBJ wires.
Function: Removes a specific item from the entry list.
const listItem = button.parentElement;listItem.remove();updateTotalWeightAndWireFill();
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Function: Resets the current list of entries.
document.getElementById('entryList').innerHTML = '';entryList)
document.getElementById('totalWeight').innerText = '0 lbs';
document.getElementById('wireFill').innerText = '0%';
totalWeight and wireFill)
document.getElementById('conduitType1').selectedIndex = 0;
document.getElementById('conduitSize1').selectedIndex = 0;
document.getElementById('conduitLength1').value = '10';
document.getElementById('wireType1').selectedIndex = 0;
document.getElementById('wireSize1').selectedIndex = 0;
document.getElementById('wireLength1').value = '10';
document.getElementById('wireCount1').value = '1';
document.getElementById('freeAir').checked = false;
toggleFreeAir();
conduitType1, conduitSize1, conduitLength1, wireType1, wireSize1, wireLength1, wireCount1, and freeAir)populateConduitSizes(document.getElementById('conduitSize1'), 'Western Tube EMT');populateWireSizes(document.getElementById('wireSize1'));
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Handles checking ampacity based on wire size, temperature rating, and derating factors.
Function: Initiates an ampacity check for a specific set of wires.
const setItem = document.getElementById(`set-${setId}`);set-${setId})const conductorDetails = extractConductorDetails(setItem.innerText);extractConductorDetails().showAmpacityResults(setId, conductorDetails);Function: Extracts conductor details from a given text input.
const conduitMatch = text.match(/Conduit: Type - ([^,]+)/);const wireMatches = text.match(/Wire: Type - (\w+-?\w*), Size - (\d+\/?\d*), Length - (\d+) ft, Count - (\d+)/g);
if (conduitMatch) {
conduitType = conduitMatch[1];
} else {
conduitType = "No Conduit";
}
if (wireMatches) {
wireMatches.forEach(match => {
const details = {};
const matchDetails = match.match(/Wire: Type - (\w+-?\w*), Size - (\d+\/?\d*), Length - (\d+) ft, Count - (\d+)/);
if (matchDetails) {
details.wireType = matchDetails[1];
details.wireSize = matchDetails[2];
details.wireLength = parseInt(matchDetails[3]);
details.wireCount = parseInt(matchDetails[4]);
detailsList.push(details);
}
});
}
return { conduitType, detailsList };
Function: Retrieves the base ampacity for a given wire size and temperature rating.
if (ampacityData.ampacity[wireSize] && ampacityData.ampacity[wireSize][tempRating]) {
return ampacityData.ampacity[wireSize][tempRating];
}
ampacityData based on wire size and temperature rating.return ampacityData.ampacity[wireSize][tempRating];Function: Applies derating factors based on the number of wires.
for (let range in ampacityData.ccc_derating) {
const [min, max] = range.includes('and above') ? [parseInt(range), Infinity] : range.split('-').map(Number);
if ((max && wireCount >= min && wireCount <= max) || (!max && wireCount >= min)) {
deratingFactor = ampacityData.ccc_derating[range];
break;
}
}
ampacityData.ccc_derating to find the appropriate derating factor based on wire count.return baseAmpacity * deratingFactor;Function: Calculates the ampacities of wires considering conduit type and temperature rating.
const totalWireCount = detailsList.reduce((total, details) => total + details.wireCount, 0);
const ampacities = detailsList.map(details => {
let baseAmpacity;
if (conduitType === "Free Air" || conduitType === "No Conduit") {
baseAmpacity = freeAirCopperData[details.wireSize] ? freeAirCopperData[details.wireSize][tempRating] : undefined;
} else {
baseAmpacity = getBaseAmpacity(details.wireSize, tempRating);
}
...
if (baseAmpacity === undefined) {
return { wireSize: details.wireSize, wireType: details.wireType, ampacity: 'N/A' };
}
let deratedAmpacity;
if (conduitType === "Free Air" || conduitType === "No Conduit") {
deratedAmpacity = baseAmpacity;
} else {
deratedAmpacity = applyDerating(baseAmpacity, totalWireCount);
}
return { wireSize: details.wireSize, wireType: details.wireType, ampacity: deratedAmpacity };
return ampacities;Function: Applies ambient temperature derating to the calculated ampacities.
const deratingFactor = ampacityData.ambient_temp_derating[tempRating].find(([tempRange, factor]) => {
const [minTemp, maxTemp] = tempRange.split('-').map(Number);
return ambientTemperature >= minTemp && ambientTemperature <= maxTemp;
})[1];
return ampacities.map(ampacity => {
if (ampacity.ampacity === 'N/A') return ampacity;
return { ...ampacity, ampacity: ampacity.ampacity * deratingFactor };
});
Function: Displays the ampacity results.
const tempRating = prompt('Enter the temperature rating (60, 75, or 90°C):');const ampacities = calculateAmpacities(conductorDetails.detailsList, tempRating, conductorDetails.conduitType);
if (ambientTemperature) {
ampacities = applyAmbientTemperatureDerating(ampacities, ambientTemperature, tempRating);
}
document.getElementById('ampacityResults').innerHTML = ampacities.map(ampacity => {
return `${ampacity.wireType} ${ampacity.wireSize}: ${ampacity.ampacity}A`;
}).join('
');
ampacityResults)Contains functions for calculating the total weight and wire fill percentage.
Function: Calculates the total weight of conduits and wires, determines the fill percentage, and adds the set to the list.
let totalWeight = 0;
let totalWireArea = 0;
let totalConduitArea = 0;
let numConductors = 0;
let hasFreeAir = false;
const listItems = document.getElementById('entryList').getElementsByTagName('li');
for (let item of listItems) {
const text = item.innerText;
...
if (text.startsWith('Conduit:')) {
const typeMatch = text.match(/Type - ([^,]+)/);
const sizeMatch = text.match(/Size - ([^,]+)/);
const lengthMatch = text.match(/Length - ([^ ]+)/);
if (typeMatch && sizeMatch && lengthMatch) {
const type = typeMatch[1];
const size = sizeMatch[1];
const length = parseFloat(lengthMatch[1]);
if (type === "Free Air") {
hasFreeAir = true;
} else {
const weightPerFootIndex = ["1/2", "3/4", "1", "1-1/4", "1-1/2", "2", "2-1/2", "3", "3-1/2", "4"].indexOf(size);
const weightPerFoot = conduitData[type][weightPerFootIndex];
const conduitArea = conduitSizeData[type][size];
if (weightPerFoot !== undefined && !isNaN(weightPerFoot)) {
totalWeight += weightPerFoot * length;
totalConduitArea += conduitArea;
}
}
}
}
} else if (text.startsWith('Wire:') || text.startsWith('Wire (Non-CCC):') || text.startsWith('Wire (EGC):') || text.startsWith('Wire (GEC):') || text.startsWith('Wire (SBJ):')) {
const typeMatch = text.match(/Type - ([^,]+)/);
const sizeMatch = text.match(/Size - ([^,]+)/);
const lengthMatch = text.match(/Length - ([^ ]+)/);
const countMatch = text.match(/Count - ([^ ]+)/);
if (typeMatch && sizeMatch && lengthMatch && countMatch) {
const type = typeMatch[1];
const size = sizeMatch[1];
const length = parseFloat(lengthMatch[1]);
const count = parseInt(countMatch[1]);
const wire = wireData.find(w => w.size === size);
if (wire) {
const weightPerFoot = type === 'THWN-2' ? wire.THWN2.weight / 1000 : wire.XHHW2.weight / 1000;
if (weightPerFoot !== undefined && !isNaN(weightPerFoot)) {
totalWeight += weightPerFoot * length * count;
const wireArea = type === 'THWN-2' ? wire.THWN2.area : wire.XHHW2.area;
totalWireArea += wireArea * count;
numConductors += count;
}
}
}
}
if (!hasFreeAir && totalConduitArea > 0) {
const fillPercentage = (totalWireArea / totalConduitArea) * 100;
document.getElementById('wireFill').innerText = `${fillPercentage.toFixed(2)}%`;
} else {
document.getElementById('wireFill').innerText = 'N/A';
}
document.getElementById('totalWeight').innerText = `${totalWeight.toFixed(2)} lbs`;totalWeight)Function: Allows editing of a specific set.
const setItem = document.getElementById(`set-${setId}`);set-${setId})
const conduitMatches = setItem.innerText.match(/Conduit: Type - ([^,]+), Size - ([^,]+), Length - ([^ ]+) ft/);
if (conduitMatches) {
const [_, type, size, length] = conduitMatches;
document.getElementById('conduitType1').value = type;
document.getElementById('conduitSize1').value = size;
document.getElementById('conduitLength1').value = length;
}
const wireMatches = setItem.innerText.match(/Wire: Type - ([^,]+), Size - ([^,]+), Length - ([^ ]+) ft, Count - ([^ ]+)/g);
if (wireMatches) {
wireMatches.forEach(match => {
const [_, type, size, length, count] = match.match(/Wire: Type - ([^,]+), Size - ([^,]+), Length - ([^ ]+) ft, Count - ([^ ]+)/);
document.getElementById('wireType1').value = type;
document.getElementById('wireSize1').value = size;
document.getElementById('wireLength1').value = length;
document.getElementById('wireCount1').value = count;
addWire();
});
}
setItem.remove();Contains functions for removing items and sets.
Function: Removes a specific item from the entry list.
const listItem = button.parentElement;listItem.remove();updateTotalWeightAndWireFill();
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Function: Removes a specific set from the list of sets.
const setItem = document.getElementById(`set-${setId}`);set-${setId})const weightMatch = setItem.innerText.match(/Total Weight: ([^ ]+) lbs/);
if (weightMatch) {
const setWeight = parseFloat(weightMatch[1]);
const cumulativeWeightElem = document.getElementById('cumulativeWeight');
const currentCumulativeWeight = parseFloat(cumulativeWeightElem.innerText);
cumulativeWeightElem.innerText = `${(currentCumulativeWeight - setWeight).toFixed(2)} lbs`;
}
setItem.remove();Contains functions for resetting the entry list and sets.
Function: Resets the entire list of entries and sets.
document.getElementById('entryList').innerHTML = '';entryList)document.getElementById('setsList').innerHTML = '';setsList)document.getElementById('cumulativeWeight').innerText = '0 lbs';cumulativeWeight)
document.getElementById('conduitType1').selectedIndex = 0;
document.getElementById('conduitSize1').selectedIndex = 0;
document.getElementById('conduitLength1').value = '10';
document.getElementById('wireType1').selectedIndex = 0;
document.getElementById('wireSize1').selectedIndex = 0;
document.getElementById('wireLength1').value = '10';
document.getElementById('wireCount1').value = '1';
document.getElementById('freeAir').checked = false;
toggleFreeAir();
conduitType1, conduitSize1, conduitLength1, wireType1, wireSize1, wireLength1, wireCount1, and freeAir)populateConduitSizes(document.getElementById('conduitSize1'), 'Western Tube EMT');populateWireSizes(document.getElementById('wireSize1'));
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Function: Resets the current list of entries.
document.getElementById('entryList').innerHTML = '';entryList)
document.getElementById('totalWeight').innerText = '0 lbs';
document.getElementById('wireFill').innerText = '0%';
totalWeight and wireFill)
document.getElementById('conduitType1').selectedIndex = 0;
document.getElementById('conduitSize1').selectedIndex = 0;
document.getElementById('conduitLength1').value = '10';
document.getElementById('wireType1').selectedIndex = 0;
document.getElementById('wireSize1').selectedIndex = 0;
document.getElementById('wireLength1').value = '10';
document.getElementById('wireCount1').value = '1';
document.getElementById('freeAir').checked = false;
toggleFreeAir();
conduitType1, conduitSize1, conduitLength1, wireType1, wireSize1, wireLength1, wireCount1, and freeAir)populateConduitSizes(document.getElementById('conduitSize1'), 'Western Tube EMT');populateWireSizes(document.getElementById('wireSize1'));
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Contains functions for updating the total weight and wire fill.
Function: Updates the total weight and wire fill percentage based on the current entries.
let totalWeight = 0;
let totalWireArea = 0;
let totalConduitArea = 0;
let numConductors = 0;
let hasFreeAir = false;
const listItems = document.getElementById('entryList').getElementsByTagName('li');
for (let item of listItems) {
const text = item.innerText;
...
if (text.startsWith('Conduit:')) {
const typeMatch = text.match(/Type - ([^,]+)/);
const sizeMatch = text.match(/Size - ([^,]+)/);
const lengthMatch = text.match(/Length - ([^ ]+)/);
if (typeMatch && sizeMatch && lengthMatch) {
const type = typeMatch[1];
const size = sizeMatch[1];
const length = parseFloat(lengthMatch[1]);
if (type === "Free Air") {
hasFreeAir = true;
} else {
const weightPerFootIndex = ["1/2", "3/4", "1", "1-1/4", "1-1/2", "2", "2-1/2", "3", "3-1/2", "4"].indexOf(size);
const weightPerFoot = conduitData[type][weightPerFootIndex];
const conduitArea = conduitSizeData[type][size];
if (weightPerFoot !== undefined && !isNaN(weightPerFoot)) {
totalWeight += weightPerFoot * length;
totalConduitArea += conduitArea;
}
}
}
}
} else if (text.startsWith('Wire:') || text.startsWith('Wire (Non-CCC):') || text.startsWith('Wire (EGC):') || text.startsWith('Wire (GEC):') || text.startsWith('Wire (SBJ):')) {
const typeMatch = text.match(/Type - ([^,]+)/);
const sizeMatch = text.match(/Size - ([^,]+)/);
const lengthMatch = text.match(/Length - ([^ ]+)/);
const countMatch = text.match(/Count - ([^ ]+)/);
if (typeMatch && sizeMatch && lengthMatch && countMatch) {
const type = typeMatch[1];
const size = sizeMatch[1];
const length = parseFloat(lengthMatch[1]);
const count = parseInt(countMatch[1]);
const wire = wireData.find(w => w.size === size);
if (wire) {
const weightPerFoot = type === 'THWN-2' ? wire.THWN2.weight / 1000 : wire.XHHW2.weight / 1000;
if (weightPerFoot !== undefined && !isNaN(weightPerFoot)) {
totalWeight += weightPerFoot * length * count;
const wireArea = type === 'THWN-2' ? wire.THWN2.area : wire.XHHW2.area;
totalWireArea += wireArea * count;
numConductors += count;
}
}
}
}
if (!hasFreeAir && totalConduitArea > 0) {
const fillPercentage = (totalWireArea / totalConduitArea) * 100;
document.getElementById('wireFill').innerText = `${fillPercentage.toFixed(2)}%`;
} else {
document.getElementById('wireFill').innerText = 'N/A';
}
document.getElementById('totalWeight').innerText = `${totalWeight.toFixed(2)} lbs`;totalWeight)Contains functions for checking EGC requirements.
Function: Initiates an EGC check for a specific set.
const setItem = document.getElementById(`set-${setId}`);set-${setId})const breakerSize = prompt('Enter the size of the largest breaker or fuse in the circuit (in amps):');const matchingData = getMatchingEgcData(breakerSize);const egcDetails = extractEgcDetails(setItem.innerText);extractEgcDetails().showEgcResults(egcDetails, breakerSize, matchingData);Function: Finds the appropriate EGC size based on the breaker or fuse size.
const egcSizeRange = Object.keys(egcData).find(range => {
const [min, max] = range.includes('and above') ? [parseInt(range), Infinity] : range.split('-').map(Number);
return (max && breakerSize >= min && breakerSize <= max) || (!max && breakerSize >= min);
});
return egcData[egcSizeRange];
egcData to find a matching range based on the breaker or fuse size.return egcData[egcSizeRange];Function: Extracts EGC details from a given text input.
const wireMatches = text.match(/Wire \(EGC\): Type - ([^,]+), Size - ([^,]+), Length - ([^ ]+) ft, Count - ([^ ]+)/g);
const detailsList = [];
if (wireMatches) {
wireMatches.forEach(match => {
const details = {};
const matchDetails = match.match(/Wire \(EGC\): Type - ([^,]+), Size - ([^,]+), Length - ([^ ]+) ft, Count - ([^ ]+)/);
if (matchDetails) {
details.wireType = matchDetails[1];
details.wireSize = matchDetails[2];
details.wireLength = parseInt(matchDetails[3]);
details.wireCount = parseInt(matchDetails[4]);
detailsList.push(details);
}
});
}
return detailsList;
Function: Displays the EGC results.
detailsList.forEach(details => {
const requiredSize = matchingData.size;
const actualSize = details.wireSize;
const result = compareSizes(actualSize, requiredSize);
results.push({
wireType: details.wireType,
wireSize: details.wireSize,
requiredSize,
result
});
});
document.getElementById('egcResults').innerHTML = results.map(result => {
return `Type: ${result.wireType}, Size: ${result.wireSize}, Required: ${result.requiredSize} - ${result.result ? 'OK' : 'Not OK'}`;
}).join('
');
egcResults)Contains data used for calculations and checks.
Initializes the application and handles event listeners.
Function: Initializes the application when the page is fully loaded.
document.getElementById('addConduitBtn').addEventListener('click', addConduit);
document.getElementById('addWireBtn').addEventListener('click', addWire);
document.getElementById('calculateBtn').addEventListener('click', calculateWeight);
document.getElementById('resetButton').addEventListener('click', resetList);
document.getElementById('darkModeToggle').addEventListener('click', toggleDarkMode);
populateConduitSizes(document.getElementById('conduitSize1'), 'Western Tube EMT');
populateWireSizes(document.getElementById('wireSize1'));
updateEmptyEntries('entryList');
updateEmptyEntries('setsList');
Function: Exports the conduit and wire data to a PDF.
const doc = new jsPDF();doc.text('Conduit and Wire Weight Calculator', 10, 10);
const setsList = document.getElementById('setsList').innerText;
doc.text(setsList, 10, 20);
setsList)doc.save('conduit_wire_weight_calculator.pdf');Contains utility functions for the application.
Function: Returns the allowable fill percentage based on the number of conductors.
switch (numConductors) {
case 1:
return 53;
case 2:
return 31;
default:
return 40;
}
Function: Populates a dropdown with conduit sizes based on the selected conduit type.
selectElement.innerHTML = '';
for (let size of Object.keys(conduitSizeData[conduitType])) {
const option = document.createElement('option');
option.value = size;
option.text = size;
selectElement.add(option);
}
conduitSizeData.Function: Populates a dropdown with wire sizes.
selectElement.innerHTML = '';
for (let wire of wireData) {
const option = document.createElement('option');
option.value = wire.size;
option.text = wire.size;
selectElement.add(option);
}
wireData.Function: Toggles the display of conduit type, size, and length fields based on the "Free Air" checkbox.
const freeAirCheckbox = document.getElementById('freeAir');
const conduitFields = document.getElementById('conduitFields');
if (freeAirCheckbox.checked) {
conduitFields.style.display = 'none';
} else {
conduitFields.style.display = 'block';
}
freeAir and conduitFields)Function: Updates the display if the list is empty.
const listElement = document.getElementById(listId);
if (listElement.children.length === 0) {
const emptyItem = document.createElement('li');
emptyItem.className = 'empty';
emptyItem.innerText = 'Empty';
listElement.appendChild(emptyItem);
} else {
const emptyItem = listElement.querySelector('.empty');
if (emptyItem) {
emptyItem.remove();
}
}
listId)Function: Compares two wire sizes.
const sizeOrder = ['18', '16', '14', '12', '10', '8', '6', '4', '3', '2', '1', '1/0', '2/0', '3/0', '4/0'];
const size1Index = sizeOrder.indexOf(size1);
const size2Index = sizeOrder.indexOf(size2);
return size1Index <= size2Index;