Percentage size rounding [message #1698710] |
Wed, 17 June 2015 11:44 |
Eugeniusz Kalafior Messages: 9 Registered: June 2015 |
Junior Member |
|
|
HI, I have a situation where i have about 20 columns defined for table and some of them are invisible. Invisible columns have percentage width defined as 0. When SizeConfig class calculates the percentage sizes and distributes missing pixels (fixing rounding problem) in the end of public void calculatePercentages(int space, int positionCount) { it increases width of first X columns (where X is number of "lost" pixels). In my case sometimes those are invisible columns, and this ends up with some weird stripe, not always refreshed on the right side of the table. In my opinion it would be better to do this rounding more precise. I've changed the implementation of this method from:
public void calculatePercentages(int space, int positionCount) {
if (isPercentageSizing()) {
this.isAggregatedSizeCacheValid = false;
this.availableSpace = space;
int percentageSpace = calculateAvailableSpace(space);
int sum = 0;
int real = 0;
int realSum = 0;
int fixedSum = 0;
List<Integer> noInfoPositions = new ArrayList<Integer>();
Integer positionValue = null;
for (int i = 0; i < positionCount; i++) {
positionValue = this.sizeMap.get(i);
if (positionValue != null) {
if (isPercentageSizing(i)) {
sum += positionValue;
real = calculatePercentageValue(positionValue,
percentageSpace);
} else {
real = positionValue;
fixedSum += real;
}
realSum += real;
this.realSizeMap.put(i, real);
} else {
// remember the position for which no size information
// exists needed to calculate the size for those positions
// dependent on the remaining space
noInfoPositions.add(i);
}
}
int[] correction = correctPercentageValues(sum, positionCount);
if (correction != null) {
sum = correction[0];
realSum = correction[1] + fixedSum;
}
if (!noInfoPositions.isEmpty()) {
// now calculate the size for the remaining columns
double remaining = new Double(space) - realSum;
Double remainingColSpace = remaining / noInfoPositions.size();
for (Integer position : noInfoPositions) {
sum += (remainingColSpace / space) * 100;
this.realSizeMap.put(position, remainingColSpace.intValue());
}
// If there are positions for which no size information exist,
// the size config will use 100 percent of the available space
// on percentage sizing. To handle rounding issues just set the
// sum to 100 for correct calculation results.
sum = 100;
}
if (sum == 100) {
// check if the sum of the calculated values is the same as the
// given space if not distribute the missing pixels to some of
// the other columns this is needed because of rounding issues
// on 100% with odd-numbered pixel values
int valueSum = 0;
int lastPos = -1;
for (Map.Entry<Integer, Integer> entry : this.realSizeMap.entrySet()) {
valueSum += entry.getValue();
lastPos = Math.max(lastPos, entry.getKey());
}
if (space > 0 && valueSum < space) {
// distribute the missing pixels
int missingPixels = (space - valueSum);
int pos = 0;
for (int i = missingPixels; i > 0; i--) {
if (!this.realSizeMap.containsKey(pos)) {
// there are more missing pixels than columns
// start over at position 0
pos = 0;
}
int posValue = this.realSizeMap.get(pos);
this.realSizeMap.put(pos, posValue + 1);
pos++;
}
}
}
}
}
to:
public void calculatePercentages(int space, int positionCount) {
if (isPercentageSizing()) {
this.isAggregatedSizeCacheValid = false;
this.availableSpace = space;
int percentageSpace = calculateAvailableSpace(space);
int sum = 0;
int real = 0;
int realSum = 0;
int fixedSum = 0;
List<Integer> noInfoPositions = new ArrayList<Integer>();
List<Double> endings = new ArrayList<Double>(positionCount);
Integer positionValue = null;
for (int i = 0; i < positionCount; i++) {
positionValue = this.sizeMap.get(i);
if (positionValue != null) {
if (isPercentageSizing(i)) {
sum += positionValue;
Double porcentageSize = new Double(percentageSpace) * positionValue / 100;
real = porcentageSize.intValue();
//keep the difference between int and double value of the percentage size
//to add missing pixels to columns with highest differences
endings.add(i, porcentageSize - real);
} else {
real = positionValue;
fixedSum += real;
}
realSum += real;
this.realSizeMap.put(i, real);
} else {
// remember the position for which no size information
// exists needed to calculate the size for those positions
// dependent on the remaining space
noInfoPositions.add(i);
}
}
int[] correction = correctPercentageValues(sum, positionCount);
if (correction != null) {
sum = correction[0];
realSum = correction[1] + fixedSum;
}
if (!noInfoPositions.isEmpty()) {
// now calculate the size for the remaining columns
double remaining = new Double(space) - realSum;
Double remainingColSpace = remaining / noInfoPositions.size();
for (Integer position : noInfoPositions) {
sum += (remainingColSpace / space) * 100;
this.realSizeMap.put(position, remainingColSpace.intValue());
}
// If there are positions for which no size information exist,
// the size config will use 100 percent of the available space
// on percentage sizing. To handle rounding issues just set the
// sum to 100 for correct calculation results.
sum = 100;
}
if (sum == 100) {
// check if the sum of the calculated values is the same as the
// given space if not distribute the missing pixels to columns
// with highest differences between double and int values
if (space > 0 && realSum < space) {
//sort differences between int and double values
List<Double> sortedEndings = new ArrayList<Double>(endings);
Collections.sort(sortedEndings);
//round up sizes of columns that have biggest differences between double and int value to have a total of 100% of table size
//(40.3, 20.4, 39,3) -> (40, 21, 39)
for(int i = space - realSum; i > 0; i--){
int colIndex = endings.indexOf(sortedEndings.get(sortedEndings.size()-i));
realSizeMap.put(colIndex, realSizeMap.get(colIndex) + 1);
}
}
}
}
}
or something similar.
|
|
|
|
Re: Percentage size rounding [message #1698748 is a reply to message #1698720] |
Wed, 17 June 2015 14:59 |
Eugeniusz Kalafior Messages: 9 Registered: June 2015 |
Junior Member |
|
|
I am using ColumnHideShowLayer, but I am also setting them size to 0 to I keep a total of 100% while defining columns percentage width for each of them. My proposition is actually an improvement of distributing the "lost" pixels so that if percentage calculation results in columns width like this: 50.2, 30.1, 40.8, 30.9, the final result is 50, 30, 41, 31, instead of 51, 31, 41, 30.
[Updated on: Wed, 17 June 2015 15:30] Report message to a moderator
|
|
|
|
|
|
Re: Percentage size rounding [message #1698823 is a reply to message #1698764] |
Thu, 18 June 2015 08:40 |
Eugeniusz Kalafior Messages: 9 Registered: June 2015 |
Junior Member |
|
|
Quote:As far as I can see your solution doesn't take into account that there are more than one pixels that need to be distributed.
The number of "lost" pixels will always be smaller than the number of columns, as it comes from rounding the double values only, so there will be no need to add more than one pixel to a column. If you ask about adding pixel to more than one column, it's handled in this loop:
for(int i = space - realSum; i > 0; i--){
int colIndex = endings.indexOf(sortedEndings.get(sortedEndings.size()-i));
realSizeMap.put(colIndex, realSizeMap.get(colIndex) + 1);
}
Quote: And what happens if all columns have the same rounding loss?
From my point of view it doesn't matter which one of those columns will get the additional pixel, if there is no column that have bigger rounding loss.
Quote:what impact on the performance this would have
I haven't tested it on a table with more than 100 columns, it could have impact on performance when using large amount of columns. However the most complex calculation here is sorting the list of doubles, so I don't think it would be that heavy.
Quote:Needs to be well tested for all of the possible use cases.
Of course, I totally agree. From my side I can add that I'm using this solution for my application and it works correctly.
[Updated on: Thu, 18 June 2015 08:41] Report message to a moderator
|
|
|
Powered by
FUDForum. Page generated in 0.03091 seconds