Creating a rating system for displaying rating stars in asp.net - asp.net

I've a values something like this 1.25, 2.50, 3.75 or 4.00:
I can loop on the integers like 1, 2, 3 or 4.
But how I can loop on 3.75?
for (int i = 0; i < 3.75; i++)
{
// my logic
}
Updated:
The loop I needed as I'm creating a rating system and displaying the rating stars in loop. For example:
If 1.25 then star 1 and quarter (0.25) of star 2. Or if 4.75 then star 4 and last quarter (0.75) of star.
3.75/5
How I can display rating in stars?

Prepare 2 image files, one has 5 empty-stars and the other has 5 filled-stars, just like:
the 2 images must have same width and height, e.g. 400X70
place the filled-stars overlap on the empty-stars, then crop the filled-stars to a portion of the origin witdh the same as the Rating,
i.e. the crop div width = image_width / 5 * rating
e.g. With 3.5 Rating, width = 400 / 5 * 3.5 = 280
<html>
<head><title>test</title>
<style type="text/css">
.container > * {
position: absolute;
}
.container, .crop {
height: 70px;
}
.crop {
overflow: hidden;
}
</style>
</head>
<body>
<div class="container">
<img src="https://i.stack.imgur.com/yiT2y.png" />
<!-- the width could be calculated either at server or client side, or define in css -->
<div class="crop" style="width:280px">
<img src="https://i.stack.imgur.com/oTi9e.png" />
</div>
</div>
</body>
</html>

Although generally it's not a good idea to loop on double, especially when you check for equality in the loop, in your case it's OK because your loop increment is can be represented precisely as a combination of powers of 2. Specifically, 1.25 is 20+2-2.
for (double i = 0 ; i < 6 ; i+=1.25) {
// my logic
}
Alternatively, you could loop on int, and multiply loop counter by 1.25:
for (int i = 1 ; i <= 4 ; i++) {
double val = 1.25 * i;
//
}
I'm creating a rating system and displaying the rating stars in loop.
You don't need a loop for this. If you have a number between 0 and 5, inclusive, representing the average, you need to know three things:
How many "filled" stars to display,
How big is the filled portion of of the partially-filled star, and
How many "blank" stars to display.
You can find out the answers to these three questions using math:
The number of "filled" stars is the integer portion of the number after truncation
The fraction of the partially filled star is the decimal part of the number
The number of "blank" stars is 5-ceil(n), where ceil(n) represents the "ceiling" of the number (i.e. the smallest int equal or higher than n).

Just use loop variable of type double:
for (double x = 1.25; x <= 4; x += 1.25)
{
// Your logic
}

You can iterate over a list of accepted values instead of iterating on float. If you don't want to manually edit known values, one way to generate them would be:
IEnumerable<float> CalculateBreakpoints(int min, int max, short unitPartitions)
{
var fraction = 1f / unitPartitions;
for (float i = min; i <= max; i += fraction)
{
yield return i;
}
}
It's unlikely that in the wild you'll have ratings that exactly match your known values. You could try choosing known value closest to rating at hand or approach it some other way. Amazon for example shows closest value above actual rating. That could be done like this:
float MapRatingToBreakpoint(float rating, IEnumerable<float> breakpoints)
{
var min = breakpoints.Min();
var max = breakpoints.Max();
if (rating < min || rating > max)
{
throw new ArgumentOutOfRangeException(nameof(rating));
}
foreach (var point in breakpoints)
{
if (rating <= point)
{
rating = point;
break;
}
}
return rating;
}
Once you have a processed rating, to display stars on the front end this code would be able to choose what type of star to use:
for (let i = 1; i <= 5; ++i) {
if (i <= Math.floor(rating)) {
console.log("addFullStar()");
}
else if (i > Math.ceil(rating)) {
console.log("addEmptyStar()");
}
else {
fraction = rating - i + 1;
console.log(`addPartialStar(fraction: ${fraction}`);
}
}
At this point it's up to you to choose how you want to display each type of star. You could use a sprite with all the different stars and play with CSS classes like <span class="star-0-25" /> to attach correct images. Another option for displaying a partial star could be to add full and empty star on top of each other, have empty star with hidden overflow, full star with visible overflow and adjust width of a parent tag.

Related

Alternating row background in QTextTable

I am trying to create a printable document using QTextDocument, which also includes a table, which I am adding using QTextCursor::insertTable.
However I have the requirement to use different background colors for the table rows. The table is meant to contain all days of a month, and weekends should have grey background, while workdays shall have no background.
I have tried this code:
QTextTable* table = cursor.insertTable(1, 7, normal); // 7 columns, and first row containing header
foreach (DayItem* day, month->days)
{
if (day->date.dayOfWeek() == 6 || day->date.dayOfWeek() == 7)
{
table->setFormat(background); // grey background
table->appendRows(1);
}
else
{
table->setFormat(normal); // white background
table->appendRows(1);
}
}
Now the issue with this is that the table->setFormat changes the format of the whole table, and I can't seem to find any function which lets me set the format for a row or a cell. There is formatting options for cells, however those are for the text format, and thus would not color the cell background.
I have also tried using QTextDocument::insertHTML and work with HTML tables, however Qt would not render the CSS correctly which I would use for styling the borders and so on.
How can I achieve alternating row background colors in QTextTable?
You can use QTextTableCell:setFormat to change the background color of each cell:
auto edit = new QTextEdit();
auto table = edit->textCursor().insertTable(3, 2);
for(int i = 0; i < table->rows(); ++i)
{
for(int j = 0; j < table->columns(); ++j)
{
auto cell = table->cellAt(i, j);
auto cursor = cell.firstCursorPosition();
cursor.insertText(QString("cell %1, %2").arg(i).arg(j));
auto format = cell.format();
format.setBackground(i%2 == 0 ? Qt::red : Qt::green);
cell.setFormat(format);
}
}

D3 scale fails if first value is different than zero

In this simple example: http://jsfiddle.net/2VeGY/1/
<!doctype html>
<meta charset="utf-8">
<title>single column</title>
<style>
*{margin:0,padding:0}
input{width:800px;}
nav{border:1px solid gray; width:850px;}
li{display:inline-block; height:30px; }
li:hover{opacity:0.8}
</style>
<script src="http://d3js.org/d3.v3.min.js"></script>
<body>
<input value="[{"v":0,"c":"red"},{"v":100,"c":"#005"},{"v":200,"c":"#12d"}, {"v&quo\
t;:300,"c":"#1dd"}, {"v":400,"c":"red"} ]">
<nav>
<ul>
</ul>
</nav>
<script>
var wscale = d3.scale.linear().range(["0px","800px"])
update()
d3.select("input").on("change",update)
function update(){
var data = JSON.parse(d3.select("input").property("value"));
var li=d3.select("ul").selectAll("li").data(data);
wscale.domain(d3.extent(data,function(d){return d.v}))
li.enter().append("li")
li
.style("width",function(d,i){
start=d.v
i+1 == data.length ? end=d.v : end=data[i+1].v;
return wscale(end-start)
})
.style("background-image",function(d,i){
start=d.c;
i+1 == data.length ? end=d.c : end=data[i+1].c;
return "linear-gradient(to right, "+start+","+end+")"});
li.exit().remove()
}
</script>
you can change the color scale of the steps data[...].c and their position data[...].v.
The scale is updated dynamically.
My problem is the following: Why it messes up if the first value is different than zero?
Thanks a lot for your help!
You're seeing this behaviour because with your current code, you always pass 0 as an input value to wscale. For the last li element, end is going to be the same as start in your function to set the width and therefore what you're passing to wscale will be 0. The input domain of wscale is determined as the extent of the input values and doesn't take this additional value into account.
You can easily fix this by changing how the domain is determined:
wscale.domain([0, d3.max(data,function(d){return d.v})]);
This assumes that all of your v values are positive.
However, what you really want to do is take into account the differences between the values, as that's what you're passing to the scale. That is, the total sum of differences should be equal to the maximum width. You can compute this as follows.
var sumdiff = 0;
for(var i = 0; i < data.length - 1; i++) {
sumdiff += data[i+1].v - data[i].v;
}
Then the scale becomes
wscale.domain([0, sumdiff]);
Complete example here.
you shouldn't put the quotation marks in the range, it should be like so:
.range([0,800])

css inline-block div positioning

I'm trying to fix a positing issue in a responsive design.
I have a container div, containing 4 (but it could be more or less) divs that are displayed as inline-block. I would like to know how to control the number of divs per line when the page is resized (with CSS, if it's possible). For example, when 4 containees no longer fits in the container, the last one is moved to second line. I would like in that case to have 2 containees in the first line and 2 containees in the second line. I dont know how to do that. Your help would be welcomed!
EDIT:
it could also be 6 containees, in the case the layout would be:
- 1 line of 6 blocks if it fits
- 2 lines of 3 blocks
- 3 lines of 2 blocks
- 6 lines of one
the number of containees is variable. I just want to have the same number of containees per line
the html:
<div class="container">
<div class="containee"></div>
<div class="containee"></div>
<div class="containee"></div>
<div class="containee"></div>
</div>
the css:
.containee {
width:200px;
height:200px;
display:inline-block;
background-color:tomato
}
the example can be seen here : http://cssdesk.com/uGLbq
(PS : I tried to find the solution searching the web but I dont really know the good keywords related with this topic)
You can't with CSS (AFAIK).
You can do "the math" dynamically with Javascript in real time.
In your case,
you known the width of one block (in that moment),
you can easily get the window width (in that moment),
you know the number of your block (in that moment);
Simply apply ( (1) the first time you open the page, and (2) every time the number of blocks changes, or (3) the resolution changes) the algorithm in the following code:
// EXAMPLE OF INPUT
var windowWidth = 1400; // read it...
var blockWidth = 200; // read it or use const...
var numberOfBlocks = 10; // read it...
// Calculate the maximum number of blocks per row
var maxBlocksPerRow;
for (var i=0; i < numberOfBlocks; i++) {
if ( (blockWidth * (i + 1)) > windowWidth){
maxBlocksPerRow = i;
break;
}
}
// Check the highest 0 module combination while iterating backwards
var magicNumberForMatchingBlocks = 1; // if not found, it will be 1.
for (var i = maxBlocksPerRow; i > 0 ; i--) {
if ( (numberOfBlocks % i) == 0){
magicNumberForMatchingBlocks = i;
break;
}
}
alert("With " + numberOfBlocks + " blocks, each one wide " +
blockWidth + " pixels, and a window wide " + windowWidth + " pixels,
the number of blocks per row for having always
the same number of block in any row is: " + magicNumberForMatchingBlocks);
Then use that number to populate or re-arrange the elements with Javascript or better with some Javascript library like jQuery.
html:
<div class="container">
<div class="grouped">
<div class="containee"></div>
<div class="containee"></div>
</div>
<div class="grouped">
<div class="containee"></div>
<div class="containee"></div>
</div>
</div>
css:
.containee {
width:200px;
height:200px;
display:inline-block;
background-color:tomato
}
.grouped {
float:left;
}
Try this:
.container
{
min-width: 410px;
}
Give the .containee a float:left; if the page fits for 4, they will be positioned right beside each other, else, you'll have another line of divs. You can give it as well a margin-top:5px; in case you got another line, the divs of the second line won't be glued to the divs of the first line. Note that with this approach, its not obliged to have equal number of .containee in each line, if you have 4, then you re-size, you'll have 3 - 1, then 2 - 2...etc..

why is this layout class not always working?

This is my attempt to write my own layout class for a panel of buttons (which may have between 2 and 20 buttons). Basically they should all be of a uniform size, with a constant spacing (5px) and resize appropriately.
However it doesn't always work.
Sometimes it works absolutely fine, but others it gives space for an extra column, or becomes unable to add additional columns on resizing (removing columns is fine), or something wont work. And it takes ages and seems horribly expensive in terms of computations. Reducing width seems significantly more painful in this respect for some reason.
Anyway, here it is:
package layouts
{
import mx.core.ILayoutElement;
import spark.components.supportClasses.GroupBase;
import spark.layouts.supportClasses.LayoutBase;
public class QButtonsLayout extends LayoutBase
{
public function QButtonsLayout()
{
super();
}
override public function measure():void
{
super.measure();
target.measuredHeight = 130;
}
override public function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w,h);
var tCount:int = target.numElements; // Number of elements
var tW:Number = target.width; // Width of target (button area) - somewhere between 550 and 1000px
var maxW:Number = 1; // Largest natural width of any given element
var maxH:Number = 1; // Largest natural height of any given element
var eSetW:Number = 1; // Set (to be) width of each element upon the target
var eSetH:Number = 1; // Set (to be) height of each element upon the target
var tCols:Number = 1; // Number of columns upon the target
var tRows:Number = 1; // Number of rows upon the target
for (var i:int = 0; i<tCount; i++) // Find maxW
{
var layoutElement:ILayoutElement = useVirtualLayout ? target.getVirtualElementAt(i):target.getElementAt(i);
var thisW:Number = layoutElement.getPreferredBoundsWidth();
var thisH:Number = layoutElement.getPreferredBoundsHeight();
if(thisW > maxW)
{
maxW = thisW;
};
if(thisH > maxH)
{
maxH = thisH;
};
}
tCols = Math.floor((tW-5)/(maxW+5)); //Find maximum number of columns one can fit onto the target
if(tCols>tCount) //Fix to deal with cases with low tCounts
{
tCols = tCount;
};
tRows = Math.ceil(tCount/tCols); //Find corresponding number of rows
eSetW = ((tW-5)/tCols)-5; //Set widths of elements based upon number of columns, 5s to add some space between elements
eSetH = maxH; //Takes height as the largest height
for (var j:int = 0; j<tCount; j++)
{
var layoutElement2:ILayoutElement = useVirtualLayout ? target.getVirtualElementAt(j):target.getElementAt(j);
var eRow:int = Math.floor(j/tRows); //Row of given element, taking the 1st to be zero
var eCol:int = j - eRow*tRows; // Column of given element, again taking the 1st column as zero
var _x:Number = 5 + eRow*(eSetW+5);
var _y:Number = 5 + eCol*(eSetH+5);
layoutElement2.setLayoutBoundsPosition(_x,_y);
layoutElement2.setLayoutBoundsSize(eSetW,eSetH);
}
}
}
}
Any thoughts would be much appreciated.
Criticism more than welcome.
Turns out that it's not. The layout class itself is fine, as far as calculating element positions and size is concerned.
It is actually a problem in the way in which the buttons used calculated their prefered widths. Whilst I'm not versed in the actual manner in which this happens, it was solved by removing %width values for any height and width values for graphic elements within the button skins. (Eg changing width="100%" to left="0" right="0").
I hope this might help someone, somewhere, sometime.

ASP.net repeater, scroll 3 at a time

I have a list of data that I need to display in a web page 3 at a time
The first needs to be displayed in a div called "left" , the second in a div called "centre" and the third in a div called "right".
And I need to be able to scroll through the data with a pager. And so the next 3 results will be displayed in a similar way, and so on till the end of the data set
Obviously the alternating templates in the repeater are not suitable for this.
Is there a smarter way to achieve this?
Try a loop like this
for (int i = 3; i < enumerable.length + 3; i++)
{
if (i % 3 == 0)
{
// Put it in div 1
{
else if (i % 3 == 1)
{
// put it in div 2
{
else if (i % 3 == 2)
{
// put it in div 3
{
}
The first time through, it will use div1, the second time div2, and the third time div3, and then the fourth time div1, and so on...

Resources