Art & Collectibles Price Estimator

Art & Collectibles Conceptual Price Estimator

Introduction & Your Item Details

This tool helps you develop a conceptual price estimation for an art piece or collectible by comparing it to a similar item ("base comparable") for which you have already found a price. Important: This tool does NOT provide professional appraisals or definitive market valuations. The estimate is based on your inputs and predefined illustrative adjustments. Always consult with a qualified appraiser for formal valuations.

Base Comparable Details

Please provide information about a similar item for which you have found a recent sale price or listing. This will serve as the starting point for the estimation.

Factor Adjustments

Compare your item to the base comparable item you entered across the factors relevant to its category. Select how your item differs. The tool will apply illustrative percentage adjustments.

Please select an item category in the first tab to see relevant adjustment factors.

Conceptual Estimation Summary

Please complete the previous steps to see an estimation.

Please select an item category in the first tab.

"; return; } const factors = ADJUSTMENT_FACTORS_DB[currentEstimation.itemCategory] || ADJUSTMENT_FACTORS_DB["OtherCollectible"]; if (!factors) { factorAdjustmentsContainer.innerHTML = "

No specific adjustment factors defined for this category. Generic factors will be used if available, or proceed to summary.

"; return; } currentEstimation.factorAdjustments = []; // Reset previous adjustments for this category let tableHTML = ``; factors.forEach((factor, index) => { // Initialize with default choice and adjustment const defaultChoice = factor.default || Object.keys(factor.choices)[0]; // Fallback to first choice if no default const defaultAdjustment = factor.choices[defaultChoice]; currentEstimation.factorAdjustments.push({ factorName: factor.name, userChoice: defaultChoice, // Store the text of the choice percentAdjustment: defaultAdjustment }); tableHTML += ``; }); tableHTML += `
FactorYour Item vs. Comparable (Select how your item compares)Illustrative Adjustment
${factor.name}
${factor.note || ''}
${(defaultAdjustment * 100).toFixed(0)}%
`; factorAdjustmentsContainer.innerHTML = tableHTML; // Add event listeners to new select elements factorAdjustmentsContainer.querySelectorAll('.acpe-factor-choice').forEach(selectElement => { selectElement.addEventListener('change', handleFactorChange); }); } function handleFactorChange(event) { const selectElement = event.target; const factorIndex = parseInt(selectElement.getAttribute('data-factor-index')); const selectedOptionText = selectElement.options[selectElement.selectedIndex].text; const percentAdjustment = parseFloat(selectElement.value); if (currentEstimation.factorAdjustments[factorIndex]) { currentEstimation.factorAdjustments[factorIndex].userChoice = selectedOptionText; currentEstimation.factorAdjustments[factorIndex].percentAdjustment = percentAdjustment; const displayCell = document.getElementById(`acpe_adj_display_${factorIndex}`); if(displayCell) displayCell.textContent = `${(percentAdjustment * 100).toFixed(0)}%`; } } // --- Summary Tab Logic --- function calculateAndDisplaySummary() { if (!currentEstimation.itemCategory || currentEstimation.comparable.price === null) { resultsSummaryContainer.style.display = 'none'; noEstimationYetMsg.style.display = 'block'; pdfDownloadButtonContainer.style.display = 'none'; return; } summaryItemCategory.textContent = currentEstimation.itemCategory.replace(/_/g, ' '); summaryItemDescription.textContent = currentEstimation.itemDescription; let displayCurrency = currentEstimation.comparable.currency === 'Other' ? (currentEstimation.comparable.otherSymbol || 'N/A') : getCurrencySymbol(currentEstimation.comparable.currency); summaryBaseComparablePrice.textContent = `${formatNumber(currentEstimation.comparable.price)} ${displayCurrency}`; summaryComparableCurrency.textContent = displayCurrency; summaryAdjustmentsList.innerHTML = ''; let netAdjustment = 0; currentEstimation.factorAdjustments.forEach(adj => { netAdjustment += adj.percentAdjustment; const listItem = document.createElement('li'); const adjPercentText = (adj.percentAdjustment * 100).toFixed(0) + '%'; listItem.innerHTML = `${adj.factorName} (Choice: ${adj.userChoice}): ${adjPercentText}`; summaryAdjustmentsList.appendChild(listItem); }); currentEstimation.netAdjustment = netAdjustment; summaryNetAdjustmentPercent.textContent = `${(netAdjustment * 100).toFixed(0)}%`; summaryNetAdjustmentPercent.className = netAdjustment >= 0 ? 'adjustment-positive' : 'adjustment-negative'; const adjustedPrice = currentEstimation.comparable.price * (1 + netAdjustment); // Provide a conceptual range, e.g., +/- 15% of the adjusted price const rangeFactor = 0.15; currentEstimation.estimatedLow = adjustedPrice * (1 - rangeFactor); currentEstimation.estimatedHigh = adjustedPrice * (1 + rangeFactor); summaryEstimatedValueRange.textContent = `${formatNumber(currentEstimation.estimatedLow)} - ${formatNumber(currentEstimation.estimatedHigh)} ${displayCurrency}`; resultsSummaryContainer.style.display = 'block'; noEstimationYetMsg.style.display = 'none'; pdfDownloadButtonContainer.style.display = 'block'; } function formatNumber(num, digits = 0) { if (num === null || num === undefined || isNaN(num)) return 'N/A'; return num.toLocaleString(undefined, {minimumFractionDigits: digits, maximumFractionDigits: digits}); } function getCurrencySymbol(currencyCode) { const symbols = { USD: '$', EUR: '€', GBP: '£', JPY: '¥', CAD: 'C$', AUD: 'A$', CHF: 'CHF' }; return symbols[currencyCode] || currencyCode; // Fallback to code itself } // --- PDF Generation --- const downloadPdfButton = document.getElementById('acpeDownloadPdfButton'); if (downloadPdfButton) { downloadPdfButton.addEventListener('click', generatePdfReport); } function generatePdfReport() { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF library (jsPDF) not loaded. Cannot generate PDF.'); return; } if (!currentEstimation.itemCategory || currentEstimation.comparable.price === null) { alert("Please complete all estimation steps before generating a PDF."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF(); let yPos = 20; const leftMargin = 15; const contentWidth = doc.internal.pageSize.getWidth() - (2 * leftMargin); const checkPdfPageBreak = (neededHeight = 20) => { if (yPos + neededHeight > doc.internal.pageSize.getHeight() - 20) { doc.addPage(); yPos = 20; } }; doc.setFontSize(18); doc.text("Art & Collectibles Conceptual Estimation Report", doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 10; doc.setFontSize(10); doc.text(`Report Generated: ${new Date().toLocaleDateString()}`, leftMargin, yPos); yPos += 10; doc.setLineWidth(0.5); doc.line(leftMargin, yPos, leftMargin + contentWidth, yPos); yPos += 10; doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.text("Your Item:", leftMargin, yPos); yPos += 6; doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.text(`Category: ${currentEstimation.itemCategory.replace(/_/g, ' ')}`, leftMargin + 5, yPos); yPos += 5; let wrappedDesc = doc.splitTextToSize(`Description: ${currentEstimation.itemDescription}`, contentWidth - 5); doc.text(wrappedDesc, leftMargin + 5, yPos); yPos += (wrappedDesc.length * 4) + 2; if(currentEstimation.itemNotes) { let wrappedNotes = doc.splitTextToSize(`Additional Notes: ${currentEstimation.itemNotes}`, contentWidth - 5); doc.text(wrappedNotes, leftMargin + 5, yPos); yPos += (wrappedNotes.length * 4) + 2; } yPos += 5; checkPdfPageBreak(); doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.text("Base Comparable Item:", leftMargin, yPos); yPos += 6; doc.setFontSize(10); doc.setFont(undefined, 'normal'); let compCurrency = currentEstimation.comparable.currency === 'Other' ? (currentEstimation.comparable.otherSymbol || 'N/A') : currentEstimation.comparable.currency; doc.text(`Description: ${currentEstimation.comparable.description}`, leftMargin + 5, yPos); yPos += 5; doc.text(`Price: ${formatNumber(currentEstimation.comparable.price)} ${compCurrency}`, leftMargin + 5, yPos); yPos += 5; doc.text(`Sale/Listing Date: ${currentEstimation.comparable.date}`, leftMargin + 5, yPos); yPos += 5; doc.text(`Source: ${currentEstimation.comparable.source}`, leftMargin + 5, yPos); yPos += 10; checkPdfPageBreak(currentEstimation.factorAdjustments.length * 7 + 20); // Estimate height for table doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.text("Factor Adjustments Applied:", leftMargin, yPos); yPos += 7; const head = [['Factor', 'User Assessment', 'Illustrative Adjustment']]; const body = currentEstimation.factorAdjustments.map(adj => [ adj.factorName, adj.userChoice, `${(adj.percentAdjustment * 100).toFixed(0)}%` ]); doc.autoTable({ startY: yPos, head: head, body: body, theme: 'grid', headStyles: { fillColor: [52, 86, 139] }, // primary-color styles: { fontSize: 9, cellPadding: 2 }, margin: {left: leftMargin, right: leftMargin}, didDrawPage: function(data) { yPos = data.cursor.y + 5; } }); yPos = doc.autoTable.previous.finalY + 10; checkPdfPageBreak(); doc.setFontSize(11); doc.setFont(undefined, 'bold'); doc.text(`Net Illustrative Adjustment Percentage: ${(currentEstimation.netAdjustment * 100).toFixed(0)}%`, leftMargin, yPos); yPos += 10; doc.setFontSize(12); doc.setFont(undefined, 'bold'); doc.setFillColor(230, 240, 255); // Light blue background for final estimate doc.rect(leftMargin - 2, yPos - 7, contentWidth + 4, 18, 'F'); doc.setTextColor(52, 86, 139); // primary-color doc.text("Conceptual Adjusted Estimated Value Range:", leftMargin, yPos); yPos += 7; doc.setFontSize(14); doc.text(`${formatNumber(currentEstimation.estimatedLow)} - ${formatNumber(currentEstimation.estimatedHigh)} ${compCurrency}`, leftMargin, yPos); yPos += 15; doc.setTextColor(0,0,0); // Reset color checkPdfPageBreak(); doc.setFontSize(8); doc.setFont(undefined, 'italic'); doc.text("Disclaimer: This report is a conceptual estimation based on user-provided data and predefined illustrative adjustments. It is not a professional appraisal and should not be used for financial, legal, or insurance purposes. Consult a qualified appraiser for formal valuations.", leftMargin, yPos, {maxWidth: contentWidth}); doc.save("Art_Collectible_Estimation_Report.pdf"); } // --- Initial Load --- if (itemCategorySelect) { // Ensure element exists before adding listener itemCategorySelect.addEventListener('change', renderFactorAdjustmentsTable); } else { console.error("Item category select element not found."); } // Initial call to setup tabs and default states if (TABS_ELEMENTS.length > 0) { switchTab(0); } else { console.error("Tab button elements not found for initialization."); } });
Scroll to Top