File

src/components/am-rating/am-rating.tsx

Description

A simple rating component using StencilJS

Metadata

tag am-rating
styleUrl am-rating.css
shadow true

Index

Properties
Methods

Methods

componentWillLoad
componentWillLoad()

Once the component is loaded do the setup

Returns : void
createRatingItems
createRatingItems()

Create rating items

Returns : void
handleMouseDown
handleMouseDown(event)

Handle the mouse being pressed and update the internal rating

Parameters :
Name Optional
event No
Returns : void
render
render()

When the state changes, render the view

Returns : any
updateRating
updateRating(newRating)
Parameters :
Name Optional
newRating No
Returns : void

Properties

allowHalfRatings
allowHalfRatings: boolean
Type : boolean
Default value : false
Decorators :
@Prop()

Determines if half ratings are allowed

colorOff
colorOff: string
Type : string
Default value : "#ffffff"
Decorators :
@Prop()

The color to fill the rating with when it's outwith the max

colorOn
colorOn: string
Type : string
Default value : "#000000"
Decorators :
@Prop()

The color to fill the rating with when it's within the max

colorOutline
colorOutline: string
Type : string
Default value : "#666666"
Decorators :
@Prop()

The color to fill the rating with when it's outwith the max

direction
direction: string
Type : string
Default value : "ltr"
Decorators :
@Prop()

The direction of the shading. Valid settings are 'ltr' (left to right) and 'ttb' (top to bottom)

Private directionSettings
directionSettings: object
Type : object
Default value : { 'ltr' : { "x1" : "0", "x2" : "1","y1" : "0","y2" : "0" }, 'ttb' : { "x1" : "0", "x2" : "0","y1" : "0","y2" : "1" } }

Specifies the available gradient directions

interactive
interactive: boolean
Type : boolean
Default value : false
Decorators :
@Prop()

Determines if the user can set a rating

Private internalRating
internalRating: number
Type : number
Default value : 0

Keeps the internal rating (prop rating cannot be reassigned)

maxRating
maxRating: number
Type : number
Default value : 5
Decorators :
@Prop()

The maximum rating possible

minRating
minRating: number
Type : number
Default value : 0
Decorators :
@Prop()

The minimum rating possible

rating
rating: number
Type : number
Default value : 0
Decorators :
@Prop()

The rating

ratingItems
ratingItems: Array<object>
Type : Array<object>
Default value : []
Decorators :
@State()

The rating items, set once the component is loaded

ratingUpdated
ratingUpdated: EventEmitter
Type : EventEmitter
Decorators :
@Event()

Event fired when the rating is updated by user input

reference
reference: string
Type : string
Default value : "rating-component"
Decorators :
@Prop()

The rating identifier

svgPoints
svgPoints: string
Type : string
Default value : "48 75 18.6107374 90.4508497 24.2235871 57.7254249 0.447174185 34.5491503 33.3053687 29.7745751 48 0 62.6946313 29.7745751 95.5528258 34.5491503 71.7764129 57.7254249 77.3892626 90.4508497"
Decorators :
@Prop()

This is a star!

svgViewBox
svgViewBox: string
Type : string
Default value : "0 0 100 100"
Decorators :
@Prop()

The view box for the SVG

import { Component, Prop, State, Event, EventEmitter } from '@stencil/core';
/**
 * A simple rating component using StencilJS
 */
@Component({
  tag: 'am-rating',
  styleUrl: 'am-rating.css',
  shadow: true
})
export class AMRating {
   /**
   * The rating identifier
   */
  @Prop() reference: string = "rating-component";

   /**
   * Determines if the user can set a rating
   */
  @Prop() interactive: boolean = false;

  /**
   * The rating
   */
  @Prop() rating: number = 0;

  /**
   * The minimum rating possible
   */
  @Prop() minRating: number = 0;

  /**
   * The maximum rating possible
   */
  @Prop() maxRating: number = 5;

   /**
   * Determines if half ratings are allowed
   */
  @Prop() allowHalfRatings: boolean = false;

  /**
   * This is a star!
   */
  @Prop() svgPoints: string = "48 75 18.6107374 90.4508497 24.2235871 57.7254249 0.447174185 34.5491503 33.3053687 29.7745751 48 0 62.6946313 29.7745751 95.5528258 34.5491503 71.7764129 57.7254249 77.3892626 90.4508497";

  /**
   * The rating items, set once the component is loaded
   */
  @State() ratingItems: Array<object> = [];

  /**
   * The color to fill the rating with when it's within the max
   */
  @Prop() colorOn: string = "#000000";

  /**
   * The color to fill the rating with when it's outwith the max
   */
  @Prop() colorOff: string = "#ffffff";

  /**
   * The color to fill the rating with when it's outwith the max
   */
  @Prop() colorOutline: string = "#666666";

   /**
   * The direction of the shading.
   * Valid settings are 'ltr' (left to right) and 'ttb' (top to bottom)
   */
  @Prop() direction: string = "ltr";

   /**
   * The view box for the SVG
   */
  @Prop() svgViewBox: string = "0 0 100 100";

  /**
   * Event fired when the rating is updated by user input
   */
  @Event() ratingUpdated: EventEmitter;

  /**
   * Keeps the internal rating (prop rating cannot be reassigned)
   */
  private internalRating: number = 0;

  /**
   * Specifies the available gradient directions
   */
  private directionSettings = {
    'ltr' : { "x1" : "0", "x2" : "1","y1" : "0","y2" : "0" },
    'ttb' : { "x1" : "0", "x2" : "0","y1" : "0","y2" : "1" }
  };

  /**
   * Once the component is loaded do the setup
   */
  componentWillLoad() {
    this.internalRating = this.rating;
    this.createRatingItems();
  }

  /**
   * Create rating items
   */
  createRatingItems(){
    let items = [];

    const ratingFloor = Math.floor(this.internalRating);
    const ratingRemainder = this.internalRating % 1 * 100;

    for(var i = 0; i < this.maxRating; i++){
      const itemPercent = i < ratingFloor ? 100 : ( ratingFloor === i ? ratingRemainder : 0 );

      items.push({
        svgPoints : this.svgPoints,
        percent :  itemPercent + "%"
      });
    }

    this.ratingItems = items;
  }

  /**
   * Handle the mouse being pressed and update the internal rating
   */
  handleMouseDown(event) {
    let svgElement =  event.path[2];

    if(!svgElement.getBBox || !this.interactive){

      return;
    }

    const clickPos = event.offsetX;
    const svgWidth = svgElement.getBBox().width ;
    const clickPercentage = svgWidth/100*clickPos;

    let newRating = 0;
    while((svgElement=svgElement.previousSibling)!=null) ++newRating;

    newRating = this.allowHalfRatings ? ( newRating + (clickPercentage < 50 ? + 0.5 : 1) ) : ++newRating;
    this.updateRating( newRating );
  }

  updateRating(newRating){
    this.internalRating = newRating;
    this.createRatingItems();

    this.ratingUpdated.emit( {
      'reference' : this.reference,
      'rating' : this.internalRating
    });
  }

  /**
   * When the state changes,
   * render the view
   */
  render() {
    return (
      <div>
        {this.ratingItems.map( (ratingItem) =>
        <svg
          viewBox={this.svgViewBox}
          version="1.1"
          width='12px'
          height = '12px'
          xmlns="http://www.w3.org/2000/svg"
          class="rating-item"
          onMouseDown={ () => this.handleMouseDown(event) }
          >
            <defs>
              <linearGradient
                id={"fill-" + ratingItem['percent']}
                x1={this.directionSettings[this.direction]['x1']}
                x2={this.directionSettings[this.direction]['x2']}
                y1={this.directionSettings[this.direction]['y1']}
                y2={this.directionSettings[this.direction]['y2']}
              >
                <stop offset={ratingItem['percent']} stop-color={this.colorOn} stop-opacity="1"/>
                <stop offset={ratingItem['percent']}  stop-color={this.colorOff} stop-opacity="1"/>
              </linearGradient>
            </defs>
            <g
              stroke="none"
              stroke-width="1">
                <polygon
                  id="star"
                  stroke={this.colorOutline}
                  stroke-width="1"
                  class={"rating-item-shape rating-item-shape-fill-percent-" + ratingItem['percent']}
                  fill={"url(#fill-" +  ratingItem['percent'] + ")"}
                  points={ ratingItem['svgPoints'] }>
              </polygon>
            </g>
        </svg>
        )}
      </div>
    );
  }
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""