Part 1 – Five Star Component
This is a fully working ‘Five Star’ display for data binding – and input control for raising events. The user can adjust the graphics for the on and off stars. When clicked on, the component will raise the on_up event passing the value back to be used in actions with the normal square brackets syntax (e.g. [value]).
Here is all of the javascript along with two graphics to use for the star_images in star_ratings.zip.
Scroll down to part 2 of the tutorial to see the version which supports half stars star_ratings_half.zip.
There are three main sections in the code below. Lets go through them in order.
1) RegisterComponent and Init. This sets up the properties for our component which is the ability to change the value and the graphics for the star’s on and off state. The init function explicitly creates the star images and positions them inside the component each taking 20% of the horizontal space each. We also listen for the ‘on_up’ event so this can be used as an input control as well as display.
2) Then we have the ‘on_up’ event which takes the users input from mouse, touch, pen or gesture and works out what to do. We take this position multiply it by the five stars and divide it by the overall width of the component to work out which star they clicked on. We also store this back into the value for the properties of this component and raise the event should users want to add actions when people rate something.
3) Finally we have the ‘drawing’ function which updates the stars based on an incoming value when databinding, or from a users click. This looks up the images we have to use and the current value from the data store. It then assigns the right star picture to the five images we created in step 1.
That’s literally all there is to this really cool and functional component.
registerComponent("Five Star", "", "Five Star", "Five Star control", "five_star_init", "", "five_star_refresh", "number:value:0:0:5,imagepicker:StarOn:star_on.png,imagepicker:StarOff:star_off.png", "On Release", "", 11,49,88,53); function five_star_init(width, height) { //create five stars var star1 = createComponent(self, 'image', 0, 0, 20, 100); var star2 = createComponent(self, 'image', 20, 0, 40, 100); var star3 = createComponent(self, 'image', 40, 0, 60, 100); var star4 = createComponent(self, 'image', 60, 0, 80, 100); var star5 = createComponent(self, 'image', 80, 0, 100, 100); //setup default value setData(self, "value",0) //assign star images five_star_draw() //Bind any events to the main component or subcomponents bindEvent(self, 'on_up', 'five_star_on_up'); } function five_star_refresh(width, height) { five_star_draw() } function five_star_on_up(x, y, tid){ //work out how many stars to show var width = Number(getProperty(self,"width")) var value_real = ((x / width) * 5.0) + 1.0 var value = Math.floor(value_real) if (value_real<1.4){ //special case for zero is first 40% of first star! setData(self,"value",0) }else{ setData(self,"value",value) } five_star_draw() //now raise the event raiseEvent(self, 'On Release','{"value":' + value + '}'); } function five_star_draw(){ var value = getData(self,"value") var star1 = getComponentChild(self, 0) var star2 = getComponentChild(self, 1) var star3 = getComponentChild(self, 2) var star4 = getComponentChild(self, 3) var star5 = getComponentChild(self, 4) var staron = getData(self,"StarOn") var staroff = getData(self,"StarOff") //assign star images setProperty(star1,"filename",staroff) setProperty(star2,"filename",staroff) setProperty(star3,"filename",staroff) setProperty(star4,"filename",staroff) setProperty(star5,"filename",staroff) if (value>=1) setProperty(star1,"filename",staron) if (value>=2) setProperty(star2,"filename",staron) if (value>=3) setProperty(star3,"filename",staron) if (value>=4) setProperty(star4,"filename",staron) if (value>=5) setProperty(star5,"filename",staron) }
Part 2 – Five Star HALF Component
OK, lets look at a new control which is able to handle half stars. e.g. 0.0 stars, 0.5 stars, 1.0 stars, 1.5 stars, 2.0 stars, 2.5 stars, 3.0 stars, 3.5 stars, 4.0 stars, 4.5 stars, 5.0 stars.
Here is a zip with the javascript and graphics for this five star half component star_ratings_half.zip
The primary change is to allow real numbers (fractions) not whole numbers (integers). A new graphic, the starhalf graphic. We also used a loop in the new version of section three to reduce the amount of code. This now has to check three possible states, no star, half a star or a whole star. So we loop over each of the 5 stars rather than write that out in full!
registerComponent("Five Star Half", "", "Five Star Half", "Five Star Half control", "five_star_half_init", "", "five_star_half_refresh", "real:value:0:0:5,imagepicker:StarOn:star_on.png,imagepicker:StarOff:star_off.png,imagepicker:StarHalf:star_half.png", "On Release", "", 11,49,88,53); function five_star_half_init(width, height) { //create five stars var star1 = createComponent(self, 'image', 0, 0, 20, 100); var star2 = createComponent(self, 'image', 20, 0, 40, 100); var star3 = createComponent(self, 'image', 40, 0, 60, 100); var star4 = createComponent(self, 'image', 60, 0, 80, 100); var star5 = createComponent(self, 'image', 80, 0, 100, 100); //setup default value setData(self, "value",0) //assign star images five_star_half_draw() //Bind any events to the main component or subcomponents bindEvent(self, 'on_up', 'five_star_half_on_up'); } function five_star_half_refresh(width, height) { five_star_half_draw() } function five_star_half_on_up(x, y, tid){ //work out how many stars to show var width = Number(getProperty(self,"width")) var value_real = ((x / width) * 10.0) + 1.0 var value = Math.floor(value_real) / 2.0 if (value_real<1.3){ //special case for zero on the left third of first star! setData(self,"value",0) }else{ setData(self,"value",value) } five_star_half_draw() //now raise the event raiseEvent(self, 'On Release','{"value":' + value + '}'); } function five_star_half_draw(){ var value = Number(getData(self,"value")) var stars = [] for(var i=0;i<5;i++){ stars[i] = getComponentChild(self, i) } var staron = getData(self,"StarOn") var staroff = getData(self,"StarOff") var starhalf = getData(self,"StarHalf") //assign star images for(var i=0;i<5;i++){ if (value >= i + 1.0){ setProperty(stars[i],"filename",staron) }else if(value >= i + 0.5){ setProperty(stars[i],"filename",starhalf) }else{ setProperty(stars[i],"filename",staroff) } } }