Changing JavaFX table row styling using property binding

In my current project, we had the problem that JavaFX rows in TableView had to update their style based on a property. That property would not be visible for the user in any column. In our case, the client application would receive updates from the server and change row statuses to active/inactive in TableView.

There are many guides on how to create custom row factory that updates row styles, like rterp’s excellent example. When using visible properties this is pretty straightforward since updateItem() -method is always called when the property changes.

My first solution was to create columns that have their visibility set to false. Unfortunately, JavaFX does not call updateItem() -method if the column is not visible. Next, I created a column with zero width, but that left a narrow empty space. (Though you could probably get rid of it by messing around with CSS.)

One often suggested solution is to force the whole table to refresh by changing column visibility on and off. That solution did not play well with the FlashingTableCell which I created earlier, and it is also a bit sub-optimal since it calls updateItem() -method on every row/cell.

((TableColumn) getTableView().getColumns().get(0)).setVisible(false);
((TableColumn) getTableView().getColumns().get(0)).setVisible(true);

Eventually, I ended up making a binding between row- and item-level properties and updating the binding every time the item changed.

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableRow;

/**
 * Item change makes binding between table item and table row, to force
 * UpdateItem call when active property changes and We don't
 * have to force the update it's refresh with visibility true/false
 * trick. ex.
 *
 *  ((TableColumn) getTableView().getColumns().get(0)).setVisible(false);
 *  ((TableColumn) getTableView().getColumns().get(0)).setVisible(true);
 * 
 * Binding created is a weak reference so garbage collection should work properly.
 * 
 * @author jaakkju
 * @param 
 */
public class ToggleTableRow<T extends AbstractToggleTableItem> extends TableRow<T> {
    
    private final SimpleBooleanProperty active = new SimpleBooleanProperty();
    
    /* Current Item which is bound to this table row */
    private T currentItem = null;
    
    public ToggleTableRow() {
        super();

        active.addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
            
            /* If item is the same we know that the update came 
                from actual property change and not from the row reuse */
            
            if (currentItem != null && currentItem == getItem()) {
                updateItem(getItem(), isEmpty());
            }
        });

        /*
            JavaFX reuses rows in the same way as it reuses table cells, 
            item behind the row changes ex. if row if scrolled so that it is not visible.
         */
        itemProperty().addListener((ObservableValue<? extends T> observable, T oldValue, T newValue) -> {
            
            /* When the item changes, we unbind the
                old property and start listening to the new */
            
            active.unbind();
            
            if (newValue != null) {
                active.bind(newValue.activeProperty());
                
                /* We change current item only after
                    binding since since it trickers change in the properties */
                currentItem = newValue;
            }
        });
    }

    @Override
    final protected void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        
        /* Setting disabled sets row's pseudoclass to disabled, we can use that
           value to assign inactive styling to the row. */
        
        setDisable(item != null && !item.isActive());
        setEditable(item != null && !item.isActive());
    }
}

Table items in the solution extend this simple abstract class with active boolean property.

import javafx.beans.property.SimpleBooleanProperty;
 
/**
 * Simple abstract class that has active boolean property
 * 
 * @author jaakkju
 */
abstract public class AbstractToggleTableItem {
 
    private final SimpleBooleanProperty active = new SimpleBooleanProperty(true);
 
    public AbstractToggleTableItem(boolean active) {
        this.active.set(active);
    }
 
    public SimpleBooleanProperty activeProperty() {
        return active;
    }
 
    public void setActive(boolean active) {
        this.active.set(active);
    }
 
    public boolean isActive() {
        return active.get();
    }
}

CSS styling using pseudoclasses.

.table-row-cell:disabled {
    -fx-background-color: #c1c1c1;
    -fx-control-inner-background: #c1c1c1;
}

 

Complete example with basic table implementation is available here.

Creating flashing table cell in JavaFX 8

In my current project with JavaFX, we need cells to flash when their value has been updated so that a user would notice the change. Although this sounds like an easy piece of code to write, it took three tries to get this right.

The first versions that I wrote used CSS manipulation and timer which updated the opacity value. This created a huge overhead since CSS handling in JavaFX is not effective and should be avoided in cell updateItem method if possible.

Eventually, I ended up with a solution that uses StackPane with BorderPane as a background and FadeTransition to handle the animation. Hopefully it helps if you are building something similar.

Conversation and examples can be found from Oracle forum:
https://community.oracle.com/thread/2312537

 

import java.util.Comparator;

import javafx.animation.FadeTransition;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.util.Duration;

import com.sun.javafx.scene.control.skin.LabeledText;

/**
 * 
 * @author jaakkju
 * @param <S>
 * @param <T>
 */
public class FlashingTableCell<S, T> extends TableCell<S, T> {

    private static final Color INCREASE_HIGHLIGHT_COLOR = Color.rgb(0, 255, 0, 0.8);
    private static final Color DECREASE_HIGHLIGHT_COLOR = Color.rgb(255, 0, 0, 0.8);
    private static final Color HIGHLIGHT_COLOR = Color.rgb(255, 255, 0, 0.8);
    private static final Duration HIGHLIGHT_TIME = Duration.millis(300);
    
    private final Background bgIncrease = new Background(new BackgroundFill(INCREASE_HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
    private final Background bgDecrease = new Background(new BackgroundFill(DECREASE_HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));
    private final Background bgChange = new Background(new BackgroundFill(HIGHLIGHT_COLOR, CornerRadii.EMPTY, Insets.EMPTY));

    private final BorderPane background = new BorderPane();
    private final LabeledText lblText = new LabeledText(this);
    private final FadeTransition animation = new FadeTransition(HIGHLIGHT_TIME, background);

    private final StackPane container = new StackPane();

    private T prevValue;
    private S prevItem;

    final private Comparator<T> comparator;


    public FlashingTableCell(Comparator<T> comparator, Pos alignment) {
        super();
        this.comparator = comparator;

        lblText.textProperty().bindBidirectional(textProperty());
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        setPadding(Insets.EMPTY);
        container.getChildren().addAll(background, lblText);
        container.setAlignment(alignment);
        setGraphic(container);
    }

    @Override
    protected void updateItem(T value, boolean empty) {
        super.updateItem(value, empty);

        S currentItem = getTableRow() != null && getTableRow().getItem() != null ? (S) getTableRow().getItem() : null;

        /*
         * We check that the value has been updated and that the row model/item
         * under the cell is the same. JavaFX table reuses cells so item is not
         * always the same!
         */
        boolean valueChanged = (prevValue == null && value != null)
                || (value != null && (prevValue.hashCode() != value.hashCode()));
        boolean sameItem = currentItem != null && prevItem != null && currentItem == prevItem;

        if (valueChanged && sameItem) {

            if (comparator != null) {
                int compare = comparator.compare(value, prevValue);
                if (compare > 0) {
                    background.setBackground(bgIncrease);
                } else if (compare < 0) {
                    background.setBackground(bgDecrease);
                }
            } else {
                background.setBackground(bgChange);
            }

            animation.setFromValue(1);
            animation.setToValue(0);
            animation.setCycleCount(1);
            animation.setAutoReverse(false);
            animation.playFromStart();
        }

        prevValue = value;
        prevItem = currentItem;
    }
}

Refactoring

This is a learning diary post from Uni Helsinki course Software Factory / Facebook Academy – SocketIO team. For more info about this course read  “Ready, Set, Start Coding!”.

What is refactoring?

Refactoring is a technique of improving design and implementation without (or hardly) changing the behavior of the code. It is a process of applying series of small behavior-preserving changes that clean up code, reduce the clutter, find code that smells and improve code readability. These changes should be so small that they don’t break existing unit tests, which should be run before and after each change. This way we  can reduce the risk of introducing errors.

Refactoring can be seen as a long-term investment that helps to keep your code from decaying over time.

Why we need to refactor your code?

Usually, the first time we implement something, we write code that only works without thinking too much how well it does it. When we continue writing code that only works we constantly increase the technical depth because most of the time we don’t find the best solutions and the cleanest way to implement something, or we don’t realize that a functionality or part of it already exists.

Regular refactoring is a way to ensure that this depth doesn’t grow until the code base becomes uncontrollable.

When should we do refactoring

Finding a good time for refactoring can be sometimes cumbersome since we are not implementing new functionality and it might be hard to see the value of refactoring. It is good practice to have a habit of refactoring code, for example.

  • After fixing a bug because this forces us to read code again and by doing so we might find places that could be refactored.
  • After code reviews (if they are part of your development process) as other developers might have more optimal solutions for implementing certain functionality.
  • Before merge request to verify the quality of your request and that your code meets the conventions of a project.
  • Before implementing new functionality.
  • Upon noticing you are repeating yourself.

 

How should we start refactoring

  • Extract a class – When you notice that a class is growing up into hundreds lines and it might have multiple responsibilities or the cohesion between the methods inside is low, it might be a good idea to break the class into several smaller ones.
  • Extract method (closely related to the one above) – While doing refactoring you might notice that some method inside one class is more related to another one, so move it there.
  • Rename methods – If a method name is not describing the functionality well enough.
  • Introduce explaining variable – Shortest possible code is not always the best option: If, for example, understanding what a loop, if-clause with an assign operation or a long-chained method call does takes more than a minute introducing an explanation variable could work.
  • Remove duplicate code – Remember the DRY principle (Don’t Repeat Yourself) as it is always good to keep your code neat and tidy by removing duplicate functionality.

 

Additional reading

http://sourcemaking.com/refactoring/introduction-to-refactoring
http://en.wikipedia.org/wiki/Refactoring

Getting back on track and coding

This is learning diary post from Uni Helsinki course Software Factory / Facebook academy – SocketIO team. For more info about this course read  “Ready, Set, Start Coding!”.

You can find open issues and questions I collect from past week in my quick project notes.

 Yep, where were we?

It’s been a long while since the last time I did put some hours into this project so now it’s time to get back on track.

The difference global variables in browser

var foo = ‘bar’;
console.log( delete window.foo );  // false, not deleted

Creates a variable on the variable object on the global execution context and which is the global object that on browsers is aliased as window. This creates a property on window that you cannot delete and it is also defined before the first line of code runs.

The window symbol itself, is a actually a property of the global object that it uses to point itself.  Note also that on IE8 and earlier the property created on window is not enumerable, in IE9 Chrome, Firefox and Opera it is.

foo = ‘bar’;

Creates a property on the window object implicitly. As it’s normal property and it can be deleted.

window.foo = ‘bar’;

Creates a property on the window object explicitly. It’s a normal property and can be deleted.

this.foo = ‘bar’;

Keyword this  in the global execution context references the global object, so the code is identical to case above it.

Be aware with with global variables they can be confusing
foo = ‘bar’;

function doFoo() {
foo = “Hello”; // overides global variable
}

function doBar(foo) {
console.log(foo) // does this print “Hello” or “Howdy”
}

foo();
bar(‘Howdy’);

but avoid cluttering the global object

the best practice is to creating a namespace variable, that you use for the needed properties.

var app = {};
app.foo = ‘bar’;

 Next this on the Socket.io -team.

During the weekend I have time to write about the architecture in Socket.io project.

 

Memory issues and test cases

This is learning diary post from Uni Helsinki course Software Factory / Facebook academy – SocketIO team. For more info about this course read  “Ready, Set, Start Coding!”.

You can find open issues and questions I collect from past week in my quick project notes.

Moving back to Finland

The biggest thing since last Wednesday when I did my last working hours to Software Academy and Socket.io project was moving back to Finland/Espoo. Organizing everything take more time then you ever planned for it, 2 days turn into four days so quickly that you do not notice it. Gladly, it is possible to be flexible with this course and needed working working hours can be done during a long period of time. :)

Catching up with Socket.io development

Last thing I developed was stress/load test cases for Engine.io. One thing learned was that with node.js it is impossible to have control over garbage collection, it can be called when using expose garbage collection mode in node.

e.g.
node --expose-gc test.js

in code:
global.gc();

This helps you to find out how much memory is being used in different parts of code. Problem with my code was that engine.io-client in clients[] array did not close properly and garbage collection did not work.


function loop(i) {

  clients[i] = new eioc.Socket(address);
  clients[i].onopen = function() {
    opened++;

    clients[i].onmessage = function(data){
      messages++;>
    };

    clients[i].onclose = function() {
      closed++;
      delete clients[i];
    };
  };
};

Fix to this one was just to move delete statement before creating a new client into if-clause that checked if the type of the variable was not ‘undefined’

Hopefully I would find a bigger task for the next couple of weeks, now that I have more time to put into this project. One thing before going forward is to finish stress/load test cases.

It’s not always sunny in California

This is learning diary post from Uni Helsinki course Software Factory / Facebook academy – SocketIO team. For more info about this course read  “Ready, Set, Start Coding!”.

You can find open issues and questions I collect from past week in my quick project notes.

Too long travel time

At the weekend all the members of Facebook Academy traveled to San Francisco for the kickoff hackaton meeting in Palo Alto. The trip from Paderborn to San Francisco was extremely tiring. I had to leave Paderborn the night before my flight since, there were no trains going to Dusseldorf airport early enough to catch my flight to Paris, where I had my change.  So I left Paderborn around midnight via Soest to Dortmund and finally Dusseldorf Airport for my flight around eight o’clock.

Where is this place anyway?

Hackaton weekend in San Francisco

At the first day we had a bus transportation to University of Stanford, where Jay Borenstein welcomed us to this year’s Facebook Academy. Afterwards Scott Chacon GitHub Co-Founder gave a speech ‘How to use GitHub’. I would argue that for most of the people there using GitHub is trivial, but luckily the talk was about how to use GitHub “profoundly”.

Write something…

Three interesting days in the coding hive

Next stop on was Facebook office and a meeting room, that turned out to be the geek hive for us, where we would spend the next two and a half days. Socket.io -team had a big table reserved at the middle of the room. After short and really informal introductions we gathered around the table for confronting the bugs in Socket.io.

It smells like a geek in here

 

Team Socket.io

 

From test case to fixing a feature

Win a Facebook price?

In the Hackaton I continued fixing the issue what I had started earlier issue 232, creating a simple test case for FlashSocket support in Engine.io-client. Even from the beginning the issue seemed so small that there had to be something buried.

As thought it turned out that FlashSockets was never tested and seemed that no one had ever used it in Engine.io-client. There was something wrong even though the implementation works in Socket.io.

The first encountered problem was that Engine.io did not receive flash socket policy request from web-socket-js module/flash. With the help of Roman, our second mentor, we figured out that the problem was Node.js’s way of handling messages and how fast path is implemented.

Flash policy request, a message that has no headers and contains only following:
“<policy-file-request/>”

Finally the mentors decided that Engine.io would not implement flash policy handling at all and Engine.io-client would implement a way to specify where flash policy could be downloaded. Responsibility of providing the policy would be user’s , they could easily implement own policy request handling server, as in this example.

Other obstacle on the way was that in Engine.io policy handling had some  obsolete legacy code that was never called, this caused some extra confusion on the way to finding out what was wrong.

The greatest learning experience of this whole thing was how to debug Node.js program. For anyone encountering problems with Node.js I would recommend using debug module and extensive use of debugger; – call that fires up debugger in browser.

Visiting Humble Bundle office

Facebook provided us hotel rooms for our official and after that I stayed at my friend’s place, who works at Humble Bundle and visiting their office in the center of San Francisco was one of the nicest things during my trip.

Humble Bundle will make something you want

Trudging around San Francisco

On Tuesday and Wednesday I had plenty of time on my own since my friend went back to work, so those were the days for sight seeing. Here couple of pictures from the way.

The other side of the Golden Gate Bridge

Even the firetrucks are cool in San Francisco

Next things on the list

I am planning to write stress tests from Engine.io to see how well it perform and to find out some bottlenecks in the current implementation.

Making that first pull request

This is learning diary post from Uni Helsinki course Software Factory / Facebook academy – SocketIO team. For more info about this course read  “Ready, Set, Start Coding!”.

You can find open issues and questions I collect from past week in my quick project notes.

Focusing on only one thing at a time now

Really busy week behind.  Doing studies to two universities at the same time introduces a huge problem, a day just does not have enough hours. Gladly, this is over now on the week 4 since at the University of Paderborn the exam period starts and I don’t have any lectures to attend anymore. Weird German university schedule… And also my brother was visiting me.

The weaknesses of WebSocket protocol

In the Guillermo Rauch’s book Smashing Node.js is a section that describes the weakness of WebSocket protocol and the reasons that lead to the development of Socket.io:

“close” event means that the connection was properly closed, but it does not consider unexpected network events ex. computer closes suddenly or the network is shutdown, in these cases “close” event not ever fire and the server would still keep sending data or the client would be expecting it.

Handling reconnections, WebSocket protocols does not provide mean for handling situations where the client tries to connect back to the service after a temporal disconnect. The only way for the client to reconnect would be to refresh the browser.

Broadcasting the same message to multiple client is a commonly used pattern in many real-time applications, ex. chat application usually sends message to all the participants or a multiplier game sends the move of a player to everyone else. In WebSockets the application has to implement broadcasting mechanism.

It’s not supported yet, many older browsers, firewalls, proxies or antivirus software do not support WebSocket protocol and many users might not be able to use applications implemented with this new technology.

JSON objects are not supported by WebSocket even though JavaScript applications use them constantly.

Socket.io  provides a solutions for these aforementioned issues.  It adds an additional layer of abstraction that provides a simple API for developers effectively send messages in real time web applications, handles unexpected network events by checking if client or server is still connected with heartbeat messages and timeouts. Forevermore it implements mechanisms for broadcasting messages to multiple users and it handles JSON objects automatically so developers can implements communication patterns without worrying about text to JSON conversions.

Creating that first pull request in GitHub

On last week I began to feel that I know the Socket.io structure, tools and techniques sufficiently to fix some issues reported in GitHub, but finding an issue that is up to date and current was not just a matter of simply picking one. Issues and pull requests are a bit outdated, many of them seem to be already fixed or vaguely described. Thankfully defunctzombie helped out with this confusion and confirmed that the one I selected is actually relevant.

Starting from something simple

One issue that looked like it could be easily fixed and would serve as a good point to start from is number 232 in Engine.io-client.

https://github.com/LearnBoost/engine.io-client/issues/232

Flashsocket transport functionality in Engine.io-client needs automated test cases that verify the implemented code works. All the tests in Socket.io are written using Mocha testing framework, which is a new acquaintance to me. Learning a new tool always makes things more interesting, especially, because I know that many Node.js projects use Mocha. 

Upcoming things on the list are to write test cases that give a good coverage over the tested functionality, commit changes and fill a pull request.

Next stop San Francisco

During next weekend all the participants of Facebook Academy will attend to hackaton organized in San Francisco, and I could not be more thrilled about the trip. It will be great to meet all the members of Socket.io team and our mentors.

I wonder how this thing works

This is learning diary post from Uni Helsinki course Software Factory / Facebook academy – SocketIO team. For more info about this course read  “Ready, Set, Start Coding!”.

You can find open issues and questions I collect from past week in my quick project notes.

What tools should I learn to use when I develop Socket.io?

Browserify. “This is how we write code that runs both in Node and the browser. We use it for all our clients.” – Rauch. It allows to use node.js-style module system that compile for use in the browser, it supports exporting external methods and properties using the module.exports and exports variables. With browserify we can use require(./foo); function to use core modules and many of the modules on npm. [1], [2].

Mocha. “Our test framework.” – Rauch. JavaScript test framework running on node.js and the browser. It offers pretty much everything needed for asynchronous behavior-driven and test-driven development styles. [3], [4]

Zuul. “It’s how we transport tests so that they run in browsers and phones in the cloud.” – Rauch. Zuul provides and easy way to test JavaScript on different browsers without having them installed locally. It simplifies ensuring good browser coverage and supports commonly used JavaScript testing frameworks (qunitmochatapejasmine). Furthermore, it allows to switch seamlessly to cloud based testing like saucelabs for testing with hundreds of browsers and platforms.

Debug.This module is a tiny node.js & browser debugging utility for your libraries and applications. “A tiny yet incredibly useful dependency we use in all projects is called ‘debug’.” – Rauch

It says readme so I read it

It seems like the biggest issue to tackle before writing code is that you really need to know how everything works before starting to build something on your own.

Although the codebase of Engine.io is only around 1000 lines of code, understanding how supported transport protocols (XHR/JSONP polling, WebSockets and FlashSockets) work takes some time. In my opinion, in order to understand Engine.io, Socket.io and all the related projects, readme-files and test cases that arrive with the projects are essential. They describe well how things are expected to work and how functions should behave.

When it comes to Javascript, I would recommend to read Guillermo Rauch’s book Smashing Node.js. – it has also a small section about Node.js’s way to handle connections to TCP and HTTP servers which are supporting the topic.

First thing to do at the beginning of next week is to write an additional blog post which explains concepts and technologies related to this project and creating a small example project that uses Socket.io.

Understanding the problems that raised when Engine.io was created and where is this project heading to

“The central problem this poses is: how do we switch transports without losing messages? Engine only switches from polling to another transport in between polling cycles. Since the server closes the connection after a certain timeout when there’s no activity, and the polling transport implementation buffers messages in between connections, this ensures no message loss and optimal performance.” – from Engine.io readme file.

Ok, that is a good start when trying to understand what problems we are facing – but the questions remain where this project is heading to, what functionality will be developed next or which issue needs to be fixed?

All tests passing – this is a good spot to dig deeper


Ready, Set, Start Coding!

This is the first learning diary blog post for Software Factory / Facebook Academy course at University of Helsinki – Team SocketIO – I am really hoping that this will be also be my personal kickstart to OpenSource development.

For those of you who are not familiar with the project here is some information about it. http://www.softwarefactory.cc/2013/11/25/facebook-open-academy-2014/

In short: The Computer Science department at the University of Helsinki organizes the course in collaboration with the Facebook Academy. In the course students from all over the world contribute to open source projects and receive valuable experience. Every open source project has one or more mentors that guide this new horde of young developers with their journey to open source development. I chose SocketIO project as my first option and, gladly, I was placed in it.

Time for proactivity and self organization

The course itself does not have a strict form, it should be considered as an experimental learning experience, which means the more effort we (students participating) put into developing and contributing the more we learn and get out of it.

What is SocketIO? What is it for? Who made it?

SocketIO is a JavaScript library for realtime web applications. It simplifies the creation of realtime applications for every browser and mobile device by blurring the differences between various transport mechanism. SocketIO as of version 1.0 divides into two parts: Engine.IO and Socket.IO. Both of these parts have a server side and a client side. It is created by Guillermo Rauch and, at the time of writing this blog, entry socket.io has 49 contributors. By the end of this learning experience it will certainly have a lot more.

Team SocketIO

Our main mentor is Guillermo Rauch and assisting mentor is  Roman Shtylman, another well known open source developer. There are 14 students developing in this team but only two from the University of Helsinki, including myself. (Check my quick project notes in Evernote for more info about the participants.)

Collecting pieces of information, organizing yourself and familiarizing yourself with the codebase.

As I do with every bigger assignment or a project that I have in hand, I collect the pieces of information and store them in Evernote, collect the intermediate tasks and organize them on a Trello board.

Quick project notes in Evernote (Access everywhere notes – for ideas that pop up suddenly)
https://www.evernote.com/shard/s68/sh/6ac1f3e1-312a-458b-bc5d-df0c534dbc15/d74ac3ea47bf4619d69edd74372cb26d

Organizing everything with Trello (Simplified Kanban – also available for smartphones)
https://trello.com/b/RCuUQDlY/socketio-facebook-academy-software-factory

After getting started with the development I use Trello board to organize and record tasks that I have done with the related information.

Scale a known range of numbers into another range

Sometimes in programming it is needed to scale a known number range into another range. I needed this for an exercise in Data and Information Visualization course. I knew the range of numbers I had scale into, a range between 0 – 1020 to implement a color temperature for my visualization.

Programmer’s best friend stackoverflow helped to figure out how this can be done. Alias ‘ irritate’ breaks the problem down into algebraic concept in his great reply. http://stackoverflow.com/questions/5294955/how-to-scale-down-a-range-of-numbers-with-a-known-min-and-max-value

The implementation in Java as follows:

// Scaling between 0 - 1020
int value = (int) ((((COLOR_MAX - COLOR_MIN) * (this.power - min)) / (max - min)) + COLOR_MIN);

COLOR_MIN and COLOR_MAX holds the range that we are scaling to (0 and 1020) , min and max are the maximum and minimum values of the original range and this.power is the value that we are translating.

Hopefully this help if anyone is struggling with the same problem.