DEV Community

Cover image for HeatColor UDF (based on jQuery library)
James Moberg
James Moberg

Posted on

1

HeatColor UDF (based on jQuery library)

When displaying values in a table, I like to use color to visually indicate whether the number is high or low. When displaying data on a webpage, it was trivial for us to use the jquery-heatcolor library to dynamically add color on-the-fly. This is an older library and the project's webpage disappeared and only the JS scripts were migrated to Github. I reported the lack of demo/documentation back in 2020 and finally scraped it from Archive.org, cleaned it up and shared it as a GIST.

When generating a PDF, a non-JS approach is required so I converted the JS library to a ColdFusion UDF (back in the mid-2000's) and am just now finally sharing it hopes that it will benefit others. Enjoy!

Source Code:

https://gist.github.com/JamoCA/3220867aaa5e56917221c07d0dadfdd4

<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8">
<title>ColdFusion HeatColor UDF Demo</title>
<link rel="STYLESHEET" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.32.0/css/theme.blue.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.32.0/js/jquery.tablesorter.min.js"></script>
<script>
$(function(){
$('#myTable').tablesorter();
});
</script>
<!--- 2024-09-24 ColdFusion HeatColor UDF Demo
GIST: https://gist.github.com/JamoCA/3220867aaa5e56917221c07d0dadfdd4
BLOG: https://dev.to/gamesover/heatcolor-udf-based-on-jquery-library-d5c
TWEET: https://x.com/gamesover/status/1839035629218443300
--->
</head>
<body>
<h1>ColdFusion HeatColor UDF Demo</h1>
<p>Inspired by the <a href="https://github.com/joshuanathanson/jquery-heatcolor">jQuery-heatcolor</a> library.</p>
<cfscript>
public string function heatColor(numeric num, numeric minVal=1, numeric maxVal=100, string colorStyle="greentored", numeric lightness=0, boolean reverseOrder=false) output=false hint="Generates heat colors based on min, max & current values" {
local.x = 0;
local.shft = 0;
local.position = 0;
if (arguments.reverseOrder){
local.x = arguments.minVal;
arguments.minVal = arguments.maxVal;
arguments.maxVal = local.x;
}
arguments.lightness = (arguments.lightness gte 0 && arguments.lightness lt 1) ? arguments.lightness : 0;
local.position = (arguments.num - arguments.minVal) / (arguments.maxVal - arguments.minVal);
if (arguments.colorStyle eq 'roygbiv') {
local.shft = 0.5*local.position + 1.7*(1-local.position);
} else {
local.shft = local.position + 0.2 + 5.5*(1-local.position);
}
local.x = local.shft + local.position * (2*pi());
if (arguments.colorStyle neq 'roygbiv') local.x = local.x * -1;
local.r = int((cos(local.x) + 1) * 128);
local.r = ucase(formatbasen(int(local.r + arguments.lightness * (256 - local.r)),16));
if (len(local.r) eq 1) local.r = "0" & local.r;
local.g = int((cos(local.x+pi()/2) + 1) * 128);
local.g = ucase(formatbasen(int(local.g + arguments.lightness * (256 - local.g)),16));
if (len(local.g) eq 1) local.g = "0" & local.g;
local.b = int((cos(local.x+pi()) + 1) * 128);
local.b = ucase(formatbasen(int(local.b + arguments.lightness * (256 - local.b)),16));
if (len(local.b) eq 1) local.b = "0" & local.b;
return '##' & local.r & local.g & local.b;
}
// pre-configuration
colorStyle = "greentored"; // Use "greentored" or "roygbiv"
lightness = 0;
reverseOrder = false;
</cfscript>
<table id="myTable" class="tablesorter-blue">
<thead>
<tr><th>Row</th><th>Count</th><th>Sum</th><th>Avg</th></tr>
</thead>
<tbody>
<cfoutput>
<cfloop from="1" to="15" index="thisRow">
<cfset C = randrange(20,300)>
<cfset S = randrange(200,3000)>
<cfset A = numberformat((S/C)*100, "999.00")>
<tr>
<td>#ThisRow#</td>
<td style="background-color:#heatColor(C, 20, 300, colorStyle, lightness, reverseOrder)#">#C#</td>
<td style="background-color:#heatColor(S, 200, 3000, colorStyle, lightness, reverseOrder)#">#S#</td>
<td style="background-color:#heatColor(A, 100, 15000, colorStyle, lightness, reverseOrder)#">#A#</td>
</tr>
</cfloop>
</cfoutput>
</tbody>
</table>
</body>
</html>
view raw HeatColor.cfm hosted with ❤ by GitHub

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (2)

Collapse
 
pczarn2 profile image
Pawel Czarnota

Thanks for resurrecting this, James and sharing. Sounds like it could be useful. I looked at the example code with axe DevTools, the colors chosen for some cells have some minimum contrast accessibility issue between background and foreground, but that could be easily fixed.

Collapse
 
gamesover profile image
James Moberg • Edited

On websites, I've used a JS library that auto-adjusts the contrast or delegate this effect to a short dedicated cell for visualization purposes.

CFML-wise, I've used the "colorContrast" UDF below when JS isn't available, but it only returns white or black HEX codes based on a HEX color argument.

public string function colorContrast(string color="") output=false hint="Returns black or white hex color based on passed color" {
    if (len(trim(arguments.color)) neq 6) return '000000';
    local.intRed = inputbasen(mid(arguments.color, 1, 1 ), 16);
    local.intGreen = inputbasen(mid(arguments.color, 3, 1 ),16);
    local.intBlue = inputbasen(mid(arguments.color, 5, 1 ),16);
    if ((local.intGreen gt 9) or ((local.intRed + local.intGreen + local.intBlue) gt 30)) {
        return "000000";
    }else {
        return "ffffff";
    }
}
Enter fullscreen mode Exit fullscreen mode

If you want the text to "pop", another option would be to use CSS text-shadow to add a slight shadow or glow so that the text is better contrasted against a blackened silhouette.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay