// Copyright (c) VinAudit.com, Inc. All Right Reserved. // Please contact VinAudit.com for licensing details. /************************************************************** Script Usage: **************************************************************/ var VinAudit = VinAudit || {}; VinAudit.dom = VinAudit.dom || new function() { this.loadedFiles = {}; this.loadCss = function(url) { var element = document.createElement('link'); element.setAttribute('rel', 'stylesheet'); element.setAttribute('href', url); document.getElementsByTagName('head')[0].appendChild(element); }; this.loadJs = function(url) { if (!this.loadedFiles[url]) { this.loadedFiles[url] = true; var element = document.createElement('script'); element.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(element); } }; this.get = function(id) { return document.getElementById(id); } this.fill = function(id, html) { var element = this.get(id); if (element) { element.innerHTML = html; } else if (window.console) { window.console.log('missing elem: ' + id); } } this.hide = function(id) { var element = this.get(id); if (element) { element.style.display = 'none'; } else if (window.console) { window.console.log('missing elem: ' + id); } } this.show = function(id) { var element = this.get(id); element.style.display = ''; } this.fadeIn = function(id, startDelay, fadeDelay, displayStyle) { var elem = this.get(id); if (!elem) return; if (startDelay > 0) { setTimeout(function() { VinAudit.dom.fadeIn(id, 0, fadeDelay, displayStyle); }, startDelay); } else { elem.style.opacity = 0; elem.style.filter = "alpha(opacity=0)"; elem.style.display = displayStyle || "inline-block"; elem.style.visibility = "visible"; if (fadeDelay) { var opacity = 0; var timer = setInterval(function() { opacity += 50 / fadeDelay; if (opacity >= 1) { clearInterval(timer); opacity = 1; } elem.style.opacity = opacity; elem.style.filter = "alpha(opacity=" + opacity * 100 + ")"; }, 50 ); } else { elem.style.opacity = 1; elem.style.filter = "alpha(opacity=1)"; } } } this.selectAddOption = function(select, value, text) { var option = document.createElement('option'); option.value = value; option.innerHTML = text; select.appendChild(option); } this.selectValue = function(selectId, value) { var select = document.getElementById(selectId); for (var i = 0; i < select.options.length; i++) { if (select.options[i].value == value) { select.selectedIndex = i; return; } } } }; VinAudit.utils = VinAudit.utils || new function() { var VA = VinAudit; var MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var CURRENCY_PREFIX = '$'; var MILEAGE_UNIT = 'miles'; var MILEAGE_UNIT_SHORT = 'mi'; this.setMileageUnit = function(mileageUnit, mileageUnitShort) { MILEAGE_UNIT = mileageUnit; MILEAGE_UNIT_SHORT = mileageUnitShort; } this.setCurrencyPrefix = function(currencyPrefix) { CURRENCY_PREFIX = currencyPrefix; } this.getMileageUnit = function() { return MILEAGE_UNIT; } this.getMileageUnitShort = function() { return MILEAGE_UNIT_SHORT; } this.convertMileageOutput = function(miles) { return (MILEAGE_UNIT == 'kilometers') ? Math.round(miles * 1.609344) : miles; } this.convertMileageInput = function(value) { return (MILEAGE_UNIT == 'kilometers') ? Math.round(value / 1.609344) : value; } this.formatDate = function(date) { var year = date.substring(0,4); var month = date.substring(5,7); var day = date.substring(8,10); return MONTHS[parseInt(month) - 1] + ' ' + day + ', ' + year; } this.formatCents = function(num) { return num ? CURRENCY_PREFIX + num.toFixed(2) : num; } this.formatPrice = function(num, defaultText) { if (defaultText && !num) { return defaultText; } var num = VA.utils.formatNumber(num); return num ? CURRENCY_PREFIX + num : num; } this.formatNumber = function(num) { var num = parseInt(num); if (isNaN(num)) { return null; } else { return (num + '').replace(/(\d)(?=(\d{3})$)/g, "$1,").toString(); } } this.computePrices = function(mean, stdev) { var prices = []; for (i = 0; i <= 100; i++) { var price = this.formatPrice(mean + stdev * (i - 50) / 25); prices.push(price || 'No data'); } return prices; } this.normalCdf = function(mean, sigma, to) { var z = (to-mean)/Math.sqrt(2*sigma*sigma); var t = 1/(1+0.3275911*Math.abs(z)); var a1 = 0.254829592; var a2 = -0.284496736; var a3 = 1.421413741; var a4 = -1.453152027; var a5 = 1.061405429; var erf = 1-(((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*Math.exp(-z*z); var sign = 1; if (z < 0) { sign = -1; } return (1/2)*(1+sign*erf); } this.getUrlParam = function(field) { var urlParts = window.location.search.substring(1).split('&'); for (var i = 0; i < urlParts.length; i++) { var param = urlParts[i].split('='); if (param[0] == field) { return param[1]; } } } }; VinAudit.MarketValueWidget = new function() { var VA = VinAudit; var key = 'VA_DEMO_KEY'; var vin = null; var year = null; var make = null; var model = null; var trim = null; var price = null; var period = 182; // 6 months var mileage = null; var myLineChart = null; var country = null; this.getHtml = function() { return '
' + '' + '
' + '

Below Market

' + '

Above Market

' + '

' + '
' } this.render = function(options) { if (!window.Chart || !window.Chart.types || !window.Chart.types.Line) { // "Chart" not loaded yet? Retry... setTimeout(function() { VinAudit.MarketValueWidget.render(options); }, 250); return; } vin = options.vin || ''; year = options.year || ''; make = options.make || ''; model = options.model || ''; trim = options.trim || ''; price = options.price || "0"; period = options.period || 182; mileage = options.mileage || null; key = options.key || 'VA_DEMO_KEY'; country = options.country || 'USA'; if (country == 'CAN') { VinAudit.utils.setCurrencyPrefix('C$'); VA.utils.setMileageUnit('kilometres', 'km'); } reloadWidget(true); }; this.reRender = function(options) { var oldVin = vin; var oldYear = year; var oldMake = make; var oldModel = model; var oldTrim = trim; vin = options.vin || vin; year = options.year || year; make = options.make || make; model = options.model || model; trim = options.trim || trim; price = options.price || "0"; mileage = options.mileage || mileage; reloadWidget(oldVin != vin || oldYear != year || oldMake != make || oldModel != model || oldTrim != trim); } this.destroy = function() { if (myLineChart) { myLineChart.destroy(); myLineChart = null; } } var reloadWidget = function(newVin) { var dataUrl = ''; if (vin != '') { dataUrl = 'https://marketvalue.vinaudit.com/getmarketvalue.php?key='+encodeURIComponent(key)+'&vin='+encodeURIComponent(vin)+'&period='+encodeURIComponent(period)+'&mileage='+encodeURIComponent(mileage)+'&country='+country; } else { dataUrl = 'https://marketvalue.vinaudit.com/getmarketvalue.php?key='+encodeURIComponent(key)+'&year='+encodeURIComponent(year)+'&make='+encodeURIComponent(make)+'&model='+encodeURIComponent(model)+'&trim='+encodeURIComponent(trim)+'&period='+encodeURIComponent(period)+'&mileage='+encodeURIComponent(mileage)+'&country='+country; } hideGraphElements(newVin); getJson(dataUrl, onJsonReady); }; var hideGraphElements = function(newVin) { if (newVin) { VA.dom.hide('va_mv_title'); } VA.dom.hide('va_mv_centerlabel'); VA.dom.hide('va_mv_leftlabel'); VA.dom.hide('va_mv_rightlabel'); VA.dom.hide('va_mv_statement'); VinAudit.MarketValueWidget.destroy(); }; var fadeInGraphElements = function() { VA.dom.fadeIn('va_mv_title', 0, 0); VA.dom.fadeIn('va_mv_centerlabel', 1000, 200); VA.dom.fadeIn('va_mv_leftlabel', 1000, 700); VA.dom.fadeIn('va_mv_rightlabel', 1000, 1200); VA.dom.fadeIn('va_mv_statement', 1000, 1200, 'block'); }; var getJson = function(path, success, error) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { if (success) success(JSON.parse(xhr.responseText)); } else { if (error) error(xhr); } } }; xhr.open("GET", path, true); xhr.send(); }; var onJsonReady = function(json) { //If no_data returned by API. if (!(json.success)) { VA.dom.fadeIn('va_mv_title', 0, 0); VA.dom.fill('va_mv_title_text', 'We could not find enough data to calculate the market value for this vehicle'); return; } var vehicle = json.vehicle && json.vehicle.trim() || vin; var mean = json.mean; var stdev = json.stdev; var belowtemp = json.prices.below; var abovetemp = json.prices.above; var periodStart = json.period ? VA.utils.formatDate(json.period[0]) : null; var periodEnd = json.period ? VA.utils.formatDate(json.period[1]) : null; var count = json.count || 0; var currentMileage = json.mileage; var prices = VA.utils.computePrices(mean, stdev); var below = VA.utils.formatPrice(belowtemp); var above = VA.utils.formatPrice(abovetemp); var valuePoint; if (!json.success && json.error == 'rate_limited') { VA.dom.fill('va_mv_title_text', 'Demo expired. Please contact support@vinaudit.com for licensing.' ); } else { VA.dom.fill('va_mv_vehicle1_text', vehicle); } VA.dom.fill('va_mv_certainty_text', json.certainty ? json.certainty + '%' : '0%'); VA.dom.fill('va_mv_average_text', VA.utils.formatPrice(mean) || 'Unknown'); VA.dom.fill('va_mv_leftlabel_text', below ? (below + ' or less') : 'Unknown'); VA.dom.fill('va_mv_rightlabel_text', above ? (above + ' or more') : 'Unknown'); VA.dom.fill('va_mv_marketvalue_text', below && above ? (below + ' - ' + above) : 'Unknown'); initMileageSelect(currentMileage, price); initLinkSelect('va_mv_timeperiod', 'va_mv_timeperiod_select'); var ctx = VA.dom.get('va_mv_canvas').getContext("2d"); var bgRainbow = new ColourGradient('0B3259', 'A0D9FF'); var hiRainbow = new ColourGradient('37510C', 'D0EB97'); var bgGradient = ctx.createLinearGradient(5, 0, 595, 0); bgGradient.addColorStop(0, 'rgba('+bgRainbow.rgbAt(0)+',1)'); bgGradient.addColorStop(1, 'rgba('+bgRainbow.rgbAt(100)+',1)'); var data = { labels: prices, datasets: [{ label: "", fillColor: bgGradient, strokeColor: "rgba(11,50,89,1)", pointColor: "rgba(0,0,0,0)", pointStrokeColor: "rgba(0,0,0,0)", pointHighlightFill: "rgba(220,220,220,1)", pointHighlightStroke: "rgba(0,0,0,1)", pointHitDetectionRadius: 1, data: [0.60,2.38,4.26,6.26,8.36,10.58,12.91,15.35,17.91,20.58,23.37,26.26,29.27,32.37,35.58,38.89,42.29,45.77,49.34,52.97,56.67,60.43,64.23,68.06,71.92,75.79,79.66,83.51,87.35,91.14,94.88,98.55,102.14,105.64,109.02,112.29,115.42,118.40,121.21,123.85,126.31,128.56,130.61,132.44,134.05,135.42,136.55,137.43,138.07,138.45,138.58,138.45,138.07,137.43,136.55,135.42,134.05,132.44,130.61,128.56,126.31,123.85,121.21,118.40,115.42,112.29,109.02,105.64,102.14,98.55,94.88,91.14,87.35,83.51,79.66,75.79,71.92,68.06,64.23,60.43,56.67,52.97,49.34,45.77,42.29,38.89,35.58,32.37,29.27,26.26,23.37,20.58,17.91,15.35,12.91,10.58,8.36,6.26,4.26,2.38,0.60]}] }; Chart.types.Line.extend({ name: "CustomLine", initialize: function(data) { var arrayValue = data.labels; if (Math.abs(arrayValue[1].replace(/[^0-9\.]+/g, "")) > Math.abs(price.replace(/[^0-9\.]+/g, "")) || Math.abs(price.replace(/[^0-9\.]+/g, "")) > Math.abs(arrayValue[99].replace(/[^0-9\.]+/g, ""))) { Chart.helpers.bindEvents(this, ['mouseover', 'mousemove', 'mouseout'], function(evt){ this.restoreLastActivePoint(); var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : []; var activePoint = null; if (activePoints.length > 0) { var activePoint = activePoints[Math.floor(activePoints.length/2)]; if (activePoint === this.lastActivePoint) { return; // nothing changed. } if (activePoint) { this.lastActivePoint = activePoint; this.lastActivePoint.saveFillColor = activePoint.fillColor; this.lastActivePoint.saveStrokeColor = activePoint.strokeColor; activePoint.fillColor = activePoint.highlightFill; activePoint.strokeColor = activePoint.highlightStroke; } } if (activePoint) { setTooltipConfiguration(activePoint); } else { this.restorePreHoverChartState(); } }); } Chart.types.Line.prototype.initialize.apply(this, arguments); }, restoreLastActivePoint: function() { if (this.lastActivePoint) { this.lastActivePoint.fillColor = this.lastActivePoint.saveFillColor; this.lastActivePoint.strokeColor = this.lastActivePoint.saveStrokeColor; } }, restorePreHoverChartState: function() { myLineChart.datasets[0].fillColor = bgGradient; myLineChart.update(); VA.dom.fill("va_mv_summary", "Estimates based on "+count+" similar vehicles sold" + (periodStart && periodEnd ? (" between "+periodStart+" - "+periodEnd) : '')); } }); var options = { animation: true, scaleOverride: true, scaleSteps: 1, scaleStepWidth: 200, scaleStartValue: 0, pointDot: true, showTooltips: false, bezierCurveTension: 0.3, showScale: false, tooltipFillColor: "rgba(0,0,0,.75)", tooltipFontColor: "rgba(255,255,255,1)", tooltipFontSize: 12, tooltipFontStyle: "bold", tooltipTemplate: "<%=label%>", onAnimationComplete: function() { // hack: disable animation after loading; interferes with tooltips this.options.animation = false; if (Math.abs(price.replace(/[^0-9\.]+/g, "")) > 0) { var arrayValue = data.labels; if (Math.abs(arrayValue[1].replace(/[^0-9\.]+/g, "")) <= Math.abs(price.replace(/[^0-9\.]+/g, "")) && Math.abs(price.replace(/[^0-9\.]+/g, "")) <= Math.abs(arrayValue[99].replace(/[^0-9\.]+/g, ""))) { var currentPoint = getPoint(price.replace(/[^0-9\.]+/g, ""), arrayValue); myLineChart.datasets[0].points[currentPoint[0]].fillColor = "rgba(220,220,220,1)"; myLineChart.datasets[0].points[currentPoint[0]].strokeColor = "rgba(0,0,0,.5)"; myLineChart.eachPoints(function(point) { if (point.label.replace(/[^0-9\.]+/g, "") == currentPoint[1].replace(/[^0-9\.]+/g, "") ) { point.label = VA.utils.formatPrice(price); valuePoint = point; } }); setTimeout(function() { setTooltipConfiguration(valuePoint); }, 0); } } } }; Chart.Tooltip = Chart.Element.extend({ draw : function(){ var ctx = this.chart.ctx; this.xAlign = "center"; var arrayValue = data.labels; if (Math.abs(arrayValue[1].replace(/[^0-9\.]+/g, "")) <= Math.abs(price.replace(/[^0-9\.]+/g, "")) && Math.abs(price.replace(/[^0-9\.]+/g, "")) <= Math.abs(arrayValue[99].replace(/[^0-9\.]+/g, ""))) { this.yAlign = "below"; } else { this.yAlign = "above"; } //Distance between the actual element.y position and the start of the tooltip caret var caretPadding = this.caretPadding = 2; var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding, tooltipRectHeight = this.fontSize + 2*this.yPadding, tooltipHeight = tooltipRectHeight + this.caretHeight + caretPadding; if (this.x + tooltipWidth/2 >this.chart.width){ this.xAlign = "left"; } else if (this.x - tooltipWidth/2 < 0){ this.xAlign = "right"; } if (this.y - tooltipHeight < 0){ this.yAlign = "below"; } // added to show tooltip above in case of points near to bottom of the chart if (this.y + tooltipHeight > this.chart.canvas.height - 10) { this.yAlign = "above"; } var tooltipX = this.x - tooltipWidth/2, tooltipY = this.y - tooltipHeight; ctx.fillStyle = this.fillColor; switch(this.yAlign) { case "above": //Draw a caret above the x/y ctx.beginPath(); ctx.moveTo(this.x,this.y - caretPadding); ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight)); ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight)); ctx.closePath(); ctx.fill(); break; case "below": tooltipY = this.y + caretPadding + this.caretHeight; //Draw a caret below the x/y ctx.beginPath(); ctx.moveTo(this.x, this.y + caretPadding); ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight); ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight); ctx.closePath(); ctx.fill(); break; } switch(this.xAlign) { case "left": tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight); break; case "right": tooltipX = this.x - (this.cornerRadius + this.caretHeight); break; } Chart.helpers.drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius); ctx.fill(); ctx.fillStyle = this.textColor; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2); } }); var getPoint = function(num, arr) { var curr = arr[0].replace(/[^0-9\.]+/g, ""); var diff = Math.abs (num - curr); var pointValue = new Array(2); for (var val = 0; val < arr.length; val++) { campValue = arr[val].replace(/[^0-9\.]+/g, ""); var newdiff = Math.abs (num - campValue); if (newdiff <= diff) { diff = newdiff; pointValue[0] = val; pointValue[1] = campValue; } } return pointValue; } myLineChart = new Chart(ctx).CustomLine(data, options); myLineChart.restorePreHoverChartState(); for (var pointIndex = 25; pointIndex <= 75; pointIndex += 25) { myLineChart.datasets[0].points[pointIndex].fillColor = "rgba(0,0,0,1)"; myLineChart.datasets[0].points[pointIndex].strokeColor = "rgba(0,0,0,0.5)"; } fadeInGraphElements(); var setTooltipConfiguration = function(activePoint) { if (activePoint) { var bgGradient = ctx.createLinearGradient(5, 0, 600-5, 0); bgGradient.addColorStop(0, 'rgba('+hiRainbow.rgbAt(0)+',1)'); bgGradient.addColorStop((activePoint.x-3)/590, 'rgba('+hiRainbow.rgbAt(100*activePoint.x/600)+', 1)'); bgGradient.addColorStop((activePoint.x-3)/590, 'rgba('+bgRainbow.rgbAt(100*activePoint.x/600)+', 0.85)'); bgGradient.addColorStop(1, 'rgba('+bgRainbow.rgbAt(100)+',0.85)'); myLineChart.datasets[0].fillColor = bgGradient; myLineChart.showTooltip([activePoint]); var showPrice = activePoint.label.replace('C$', '').replace('$', '').replace(',', ''); if (mean > 0 && stdev > 0) { var cdfPercent = (100*VA.utils.normalCdf(mean, stdev, showPrice)).toFixed(0); if (cdfPercent <= 50) { VA.dom.fill("va_mv_summary", "An estimated "+cdfPercent+"% of similar vehicles sold for less than "+activePoint.label+"" + (periodStart && periodEnd ? (" between "+periodStart+" - "+periodEnd) : '')); } else { VA.dom.fill("va_mv_summary", "An estimated "+(100-cdfPercent)+"% of similar vehicles sold for more than "+activePoint.label+"" + (periodStart && periodEnd ? (" between "+periodStart+" - "+periodEnd) : '')); } } } } }; var initMileageSelect = function(currentMileage, price) { currentMileage = VinAudit.utils.convertMileageOutput(currentMileage); VA.dom.fill('va_mv_mileage_text', (currentMileage ? VA.utils.formatNumber(currentMileage) + ' ' + VA.utils.getMileageUnit() : 'Unknown')); VA.dom.show('va_mv_mileage_text'); if (mileage == null) { VA.dom.show('va_mv_mileage_avg_text'); } else { VA.dom.hide('va_mv_mileage_avg_text'); } var mileageSelect = VA.dom.get('va_mv_mileage_text_dd'); mileageSelect.innerHTML = ''; var lastValue = -1; var maxI = 200; for (var i = 0; i <= maxI;) { var value = i*1000; VA.dom.selectAddOption(mileageSelect, value, VA.utils.formatNumber(value) + ' ' + VA.utils.getMileageUnit()); i += 25; if (currentMileage > value && (currentMileage < i*1000 || i > maxI)) { VA.dom.selectAddOption(mileageSelect, currentMileage, VA.utils.formatNumber(currentMileage) + ' ' + VA.utils.getMileageUnit()); } } VA.dom.selectAddOption(mileageSelect, 'input', 'Input...'); VA.dom.get('va_mv_mileage_text').onclick = function() { VA.dom.hide('va_mv_mileage_text'); VA.dom.show('va_mv_mileage_text_dd'); VA.dom.hide('va_mv_mileage_avg_text'); VA.dom.selectValue('va_mv_mileage_text_dd', currentMileage); }; mileageSelect.onchange = function() { if (mileageSelect.style.display == '') { var mileage = VA.dom.get('va_mv_mileage_text_dd').value; if (mileage == 'input') { mileage = prompt('Current mileage:', currentMileage); if (mileage !== null) { mileage = parseInt(mileage); if (isNaN(mileage) || mileage < 0 || mileage > 1000000) { mileage = null; } } if (mileage === null) { VA.dom.selectValue('va_mv_mileage_text_dd', currentMileage); return; } } VinAudit.MarketValueWidget.reRender({ 'mileage': VinAudit.utils.convertMileageInput(mileage), 'price' : price }); VA.dom.hide('va_mv_mileage_text_dd'); VA.dom.show('va_mv_mileage_text'); } }; mileageSelect.onblur = function() { mileageSelect.onchange(); }; VA.dom.show('va_mv_mileage_content'); }; var initLinkSelect = function(linkId, selectId) { VA.dom.get(linkId).onclick = function() { VA.dom.get(linkId).style.display = 'none'; VA.dom.get(selectId).style.display = ''; }; var clickNum = 0; VA.dom.get(selectId).onclick = function() { clickNum++; if (clickNum == 2) { var selectElem = VA.dom.get(selectId); var periodDays = selectElem.value; var periodText = selectElem.options[selectElem.selectedIndex].text; VA.dom.fill(linkId, periodText); VA.dom.get(selectId).style.display = 'none'; VA.dom.get(linkId).style.display = ''; clickNum = 0; period = periodDays; reloadWidget(); } }; }; var ColourGradient = function(colourStart, colourEnd) { this.startColour = colourStart; this.endColour = colourEnd; this.rgbAt = function (number) { var hex = this.colourAt(number); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return parseInt(result[1], 16) + ',' + parseInt(result[2], 16) + ',' + parseInt(result[3], 16); } this.colourAt = function (number) { return this.calcHex(number, this.startColour.substring(0,2), this.endColour.substring(0,2)) + this.calcHex(number, this.startColour.substring(2,4), this.endColour.substring(2,4)) + this.calcHex(number, this.startColour.substring(4,6), this.endColour.substring(4,6)); } this.calcHex = function(number, channelStart_Base16, channelEnd_Base16) { var minNum = 0; var maxNum = 100; var num = number; if (num < minNum) num = minNum; if (num > maxNum) num = maxNum; var numRange = maxNum - minNum; var cStart_Base10 = parseInt(channelStart_Base16, 16); var cEnd_Base10 = parseInt(channelEnd_Base16, 16); var cPerUnit = (cEnd_Base10 - cStart_Base10)/numRange; var c_Base10 = Math.round(cPerUnit * (num - minNum) + cStart_Base10); var hex = c_Base10.toString(16); return (hex.length === 1) ? ('0' + hex) : hex; } } }; // Load css + js dependencies. VinAudit.dom.loadCss('https://fonts.googleapis.com/css?family=Open+Sans'); VinAudit.dom.loadCss('https://www.vinaudit.com/widgets/marketvalue/styles.css'); VinAudit.dom.loadJs('https://www.vinaudit.com/widgets/libs/chart.js-1.0.2-h_min.js');