Friday, January 27, 2012

Gradient trick...

Aloha,
during my work at Quintiq i stumbled upon a problem when drawing lot's of linear gradients in "realtime". In our software we have a gantt chart component that could contain thousands of nodes. Each of these nodes could contain multiple so called compartments which are representing a range of values. So the node itself is visualized using a LinearGradientPaint and also each compartment is visualized with it's own LinearGradientPaint. So far this should not be a problem but now it comes...we can't really cache things because the whole gantt chart is so to say "live". This means if somewhere in the businessmodel a value changed it will affect the ganttchart in the way that the nodes and their compartments will change it's size. Another problem is that the nodes could not only have different widths but also different heights. 
The compartments are separate shapes that will drawn on top of the nodes.
And that's not enough, the chart that is visible on the screen only represents a small part of the whole data which means one could scroll horizontal which let new nodes appear on the screen and others might change their height (this is something special to this kind of graph in our software).



Long story short...we could nail the performance problem to the drawing of the linear gradients and their creation. 
So i was thinking about how to improve the drawing speed of these gradients and came to an interesting approach that i would like to share with you in this post.

First of all i created a 1px wide BufferedImage with the most common height of the nodes. Then i filled this 1px image with a linear gradient (e.g. the green one) and saved the image for later use. Everytime when there was a new color of a compartment i created an 1px gradient image for this color. 
The trick is now to use the TexturePaint to fill all these nodes which has the big advantage that it will scale the gradientimage automaticaly to the needed height. Because we have to create each gradient only once now the repaint speed could be reduced by 30ms on each repaint.

This performance problem only occured when the gantt chart became really huge with thousands of nodes, but i thought it might be interesting for you to know.

Here is a little code snippet that will give you a hint on what i did...

private BufferedImage nodeTexture;

private void init() {
    private final float[] fractions = {
        0.0f,
        0.5f,
        1.0f
    };
    private final Color[] colors = {
        Color.RED,
        Color.GREEN,
        Color.BLUE
    };
    nodeTexture = createNodeTexture(24, fractions, colors);
}

@Override
protected void paintComponent(Graphics g) {
    ...
    Graphics2D g2 = (Graphics2D) g.create();
    for (RoundRectangle2D node : nodes) {
        TexturePaint nodePaint = new TexturePaint(nodeTexture, node.getBounds());
        g2.setPaint(nodePaint);
        g2.fill(node);
    }
    g2.dispose();
    ...
}

// Method that creates a 1px wide gradient image    
private BufferedImage createNodeTexture(final int HEIGHT, float[] fractions, Color[] colors) {
    GraphicsEnvironment gfxEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsConfiguration gfxConf = gfxEnv.getDefaultScreenDevice().getDefaultConfiguration();
    BufferedImage image = gfxConf.createCompatibleImage(1, HEIGHT, Transparency.OPAQUE);
    Graphics2D g2 = image.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Point2D start = new Point2D.Double(0, 0);
    Point2D stop = new Point2D.Double(0, HEIGHT);
    final LinearGradientPaint GRADIENT_NODE = new LinearGradientPaint(
        start, 
        stop, 
        fractions, 
        colors);
    g2.setPaint(GRADIENT_NODE);
    g2.fillRect(0, 0, 1, HEIGHT);
    g2.dispose();
    return image;
} 

Before i forget it...we are hiring, so if you are looking for a job in the Java and/or C++ area please check here


That's it for today, so keep coding...

Friday, January 6, 2012

Friday Fun Component XV

Here we go again...
Today i have nothing special for you but just another traffic light component. This time the component is more compatible to different background colors because it's semitransparent.
We needed something for our software and the other traffic light component was simply too dark...so i created this one...

click to see it in action...


As you can see it comes in two versions and you could switch between both versions by using the yellowVisible property.

The frame has the color #333333 with an opacity of 50% and the inner part has the color #CCCCCC with an opacity of 50%.
Due to the transparency this component fits better on different backgroundcolors because they shine through.


This component is now also part of the SteelSeries Java Swing component library.


Well that's all for this friday, as always you could download the binary and source (as NetBeans project) here:


binary version: TrafficLight2.jar


source          : TrafficLightDemo2.zip


So enjoy the upcoming weekend and keep coding...

Monday, January 2, 2012

SteelSeries 3.9.10 (QuickRelease)

Happy new year everybody...


UPDATE: due to some minor modifications the current version is 3.9.12


I know i said it would take some months until you will see the next release but i needed some components be part of the library so i decided this morning to make a quick release and added these new things to the lib.
The new things i have added are the traffic light and light bulb you might know already from the friday fun components, another traffic light component that might fit better to different color schemes and at least 8 new indicator symbols in the IndicatorGauge. 
To give you an idea on what the stuff looks like...here they are...


The traffic lights and the light bulb...




and the eight new symbols which are just arrows pointing to different directions...




And that's all for this release...like i said a quick release with just a few new additions. You will find the new version either here on this blog on the right side or at MavenCentral.


For those of you that are interested in the progress of the SteelSeriesFX i could show you one screenshot of the current state...


As you can see i made some progress but it's still a looooooong way to go...


so stay tuned and keep coding...