Apple Watch Dials component

Cách sử dụng

<pie-chart 
 percent="{{data.percent}}"
 startGradient="#00E083"
 endGradient="#1A94FF"
/>

Em gửi code phần chart tròn tròn trong app ạ, hy vọng team Tini có thể cải thiện nó và cho nó vào core lib

index.js

Component({
  data: {
    lAngle: 0,
    rAngle: 0,
    rPlay: false,
    lPlay: false,
    mPlay: false,
    percent: 0,
    rBackground: "#1A94FF",
    lBackground: "#1A94FF",
    sBackground: "#1A94FF",
    eBackground: "#1A94FF"
  },
  onInit() {
    const { percent, startGradient, endGradient } = this.props;

    if (percent <= 50) {
      if (percent < 50 ) {
        this.setData({
          lAngle: 0,
          rAngle: percent * 180 / 50,
          percent,
          rBackground: startGradient,
          lBackground: startGradient,
          sBackground: startGradient,
          eBackground: startGradient
        })
        
      } else {
        this.setData({
          lAngle: 0,
          rAngle: percent * 180 / 50,
          percent,
          rBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          lBackground: startGradient,
          sBackground: startGradient,
          eBackground: endGradient
        })
      }
    } else {
      if (percent === 100) {
        this.setData({
          lAngle: (percent - 50) * 180 / 50,
          rAngle: 180,
          percent,
          rBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          lBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          sBackground: startGradient,
          eBackground: startGradient
        })
      } else {
        this.setData({
          lAngle: (percent - 50) * 180 / 50,
          rAngle: 180,
          percent,
          rBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          lBackground: endGradient,
          sBackground: startGradient,
          eBackground: endGradient
        })
      }
    }    
  },
  didMount() {
    setTimeout(() => {
      this.setData({
        rPlay: true,
        lPlay: true,
        mPlay: true
      });
    }, 500);
  },
  didUpdate() {},
  didUnmount() {},
  deriveDataFromProps(nextProps) {
    this.setData({
      rPlay: false,
      lPlay: false,
      mPlay: false
    });
    setTimeout(() => {
      this.setData({
        rPlay: true,
        lPlay: true,
        mPlay: true
      });
    }, 500);

    const { percent, startGradient, endGradient } = nextProps;

    if (percent <= 50) {
      if (percent < 50 ) {
        this.setData({
          lAngle: 0,
          rAngle: percent * 180 / 50,
          percent,
          rBackground: startGradient,
          lBackground: startGradient,
          sBackground: startGradient,
          eBackground: startGradient
        })
        
      } else {
        this.setData({
          lAngle: 0,
          rAngle: percent * 180 / 50,
          percent,
          rBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          lBackground: startGradient,
          sBackground: startGradient,
          eBackground: endGradient
        })
      }
    } else {
      if (percent === 100) {
        this.setData({
          lAngle: (percent - 50) * 180 / 50,
          rAngle: 180,
          percent,
          rBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          lBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          sBackground: startGradient,
          eBackground: startGradient
        })
      } else {
        this.setData({
          lAngle: (percent - 50) * 180 / 50,
          rAngle: 180,
          percent,
          rBackground: `linear-gradient(0deg, ${startGradient} 0%, ${endGradient} 100%)`,
          lBackground: endGradient,
          sBackground: startGradient,
          eBackground: endGradient
        })
      }
    } 
  },
  methods: {
  }
});

index.tcss

:root {
  --p-r-angle: 0deg;
  --p-l-angle: 0deg;
  --p-marker-angle: calc(var(--p-l-angle) + var(--p-r-angle));
}

.p-wrapper {
  width: 80px;
  height: 80px;
  position: relative;
  border-radius: 80px;
  background-color: #EBEBF0;
}

.p-wrapper::after {
  content: "";
  background: #fff;
  border-radius: 50%;
  width: 60px;
  height: 60px;
  position: absolute;
  top: 10px;
  left: 10px;
}

.t-container-l {
  width: 40px;
  height: 80px;
  overflow: hidden;
  position: absolute;
  left: 0px;
}

.t-container-r {
  width: 40px;
  height: 80px;
  overflow: hidden;
  position: absolute;
  left: 40px;
}

.t-wedge {
  width: 40px;
  height: 80px;
  position: absolute;
  top: 0;
  left: 0;
}

.t-container-l .t-wedge {
  border-radius: 0px 80px 80px 0px;
  background: rgba(26, 148, 255, 1);
  width: 40px;
  height: 80px;
  left: 40px;
  transform-origin: 0 50%;
}

.l-play {
  animation: rotate-bg-l 1500ms linear forwards;
}

.t-container-r .t-wedge {
  border-radius: 80px 0px 0px 80px;
  background: rgba(26, 148, 255, 1);
  width: 40px;
  height: 80px;
  left: -40px;
  transform-origin: 100% 50%;
}

.r-play {
  animation: rotate-bg-r 1500ms linear forwards;
}

.p-marker {
  background: rgba(26, 148, 255, 1);
  border-radius: 50%;
  height: 10px;
  width: 10px;
  position: absolute;
  top: 0;
  left: calc(50% - 5px);
}

.marker-play {
  animation: rotate-marker 1500ms linear forwards;
}

.p-end {
  transform-origin: 50% 40px;
}

@keyframes rotate-marker {
  50% {
    transform: rotateZ(var(--p-r-angle));
  }

  75%, 100% {
    transform: rotateZ(var(--p-marker-angle));
  }
}


@keyframes rotate-bg-r {
  50%, 100% {
    transform: rotateZ(min(var(--p-r-angle), 180deg));
  }
}

@keyframes rotate-bg-l {
  0%, 50% {
    transform: rotateZ(0deg);
  }

  75%, 100% {
    transform: rotateZ(var(--p-l-angle));
  }
}

index.txml

<view class="p-wrapper" style="--p-r-angle: {{rAngle}}deg;--p-l-angle: {{lAngle}}deg; --p-marker-angle: calc(var(--p-l-angle) + var(--p-r-angle));">
  <view class="t-container-l">
    <view class="t-wedge {{lPlay ? 'l-play' : ''}}" style="background: {{lBackground}};"/>
  </view>
  <view class="t-container-r" >
    <view class="t-wedge {{rPlay ? 'r-play' : ''}}" style="background: {{rBackground}};"/>
  </view>

  <block tiki:if="{{percent > 0}}">
    <view class="p-marker p-start" style="background: {{sBackground}};"/>
    <view class="p-marker p-end {{mPlay ? 'marker-play' : ''}}" style="background: {{eBackground}};"/>
  </block>
</view>

index.json

{
  "component": true,
  "usingComponents": {
  }
}

Em học theo tutorial ở đây: Apple Watch Dials - CSS Animation

3 Likes