Not showing realated info when hovering on slice of chart

Viewed 31

I've created a chart with HTML, CSS and Angular in my projects .

This is my problem:

I want to when the user hovers on the slice of chart, show only the slice that the user hovered, but in my code, this doesn't happen, it shows other slice info.

You can see a Demo here.

This is the CSS code :

@keyframes bake-pie {
  from {
    transform: rotate(0deg) translate3d(0, 0, 0);
  }
}

body {
  font-family: "Open Sans", Arial;
  background: #eee;
}

main {
  width: 400px;
  margin: 30px auto;
}

section {
  margin-top: 30px;
}

.pieID {
  display: inline-block;
  vertical-align: top;
}

.pie {
  height: 200px;
  width: 200px;
  position: relative;
  margin: 100px 30px 30px 200px;
}

.pie::before {
  content: "";
  display: block;
  position: absolute;
  z-index: 1;
  width: 192px;
  height: 192px;
  background: #fff;
  border-radius: 50%;
  top: 4px;
  left: 4px;
}

.pie::after {
  content: "";
  display: block;
  width: 120px;
  height: 2px;
  background: rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  margin: 220px auto;
}

.slice {
  position: absolute;
  width: 200px;
  height: 200px;
  cursor: pointer;
  clip: rect(0px, 200px, 200px, 101px);
  animation: bake-pie 1s;
}

.slice-content::before {
  /* content: "";
  display: block;
  position: absolute;
  z-index: 0;
  width: var(--visible-width);
  height: var(--visible-height);
  background: #fff;
  transition: 150ms;
  border-radius: 50%;
  top: 15px;
  left: 16px;
  visibility: visible; */
}

.slice div {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  background-color: black;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  clip: rect(0px, 200px, 200px, 104px);
}

p {
  font-family: Lato;
}

canvas {
  border: 2px solid rgba(0, 0, 0, 0.12);
  transition: 300ms;
  border-radius: 4px;
}

canvas:hover {
  border: 2px solid rgba(0, 0, 0, 0.54);
}

body {
  font: 16px/1.4em "Montserrat", Arial, sans-serif;
}

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.chart-text {
  /*font: 16px/1.4em "Montserrat", Arial, sans-serif;*/
  fill: #000;
  -moz-transform: translateY(0.25em);
  -ms-transform: translateY(0.25em);
  -webkit-transform: translateY(0.25em);
  transform: translateY(0.25em);
}

.chart-number {
  font-size: 0.6em;
  line-height: 1;
  text-anchor: middle;
  -moz-transform: translateY(-0.25em);
  -ms-transform: translateY(-0.25em);
  -webkit-transform: translateY(-0.25em);
  transform: translateY(-0.25em);
}

.chart-label {
  font-size: 0.2em;
  text-transform: uppercase;
  text-anchor: middle;
  -moz-transform: translateY(0.7em);
  -ms-transform: translateY(0.7em);
  -webkit-transform: translateY(0.7em);
  transform: translateY(0.7em);
}

figure {
  display: flex;
  justify-content: space-around;
  flex-direction: column;
  margin-left: -15px;
  margin-right: -15px;
}

@media (min-width: 768px) {
  figure {
    flex-direction: row;
  }
}

.figure-content,
.figure-key {
  flex: 1;
  padding-left: 15px;
  padding-right: 15px;
  align-self: center;
}

.figure-content svg {
  height: auto;
}

.figure-key {
  min-width: calc(8 / 12);
}

.figure-key [class*="shape-"] {
  margin-right: 6px;
}

.figure-key-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.figure-key-list li {
  margin: 0 0 8px;
  padding: 0;
}

.shape-circle {
  display: inline-block;
  vertical-align: middle;
  width: 32px;
  height: 32px;
  -webkit-border-radius: 50%;
  -moz-border-radius: 50%;
  border-radius: 50%;
}

.shape-fuschia {
  background-color: #ce4b99;
}

.shape-lemon-lime {
  background-color: #b1c94e;
}

.shape-blue {
  background-color: #377bbc;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

.donut-segment {
  cursor: pointer;
}

.annytab-tooltip {
  text-align: left;
  color: #ffffff;
  background: #000000;
  position: absolute;
  z-index: 100;
  font-size: 16px;
  line-height: 24px;
  padding: 15px;
  max-width: 100%;
  border-radius: 4px;
  border: 1px solid #000000;
}

.annytab-tooltip.bottom::after {
  position: absolute;
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-bottom: 10px solid #000000;
  content: "";
  top: -11px;
  right: 10px;
}

.annytab-tooltip.top::after {
  position: absolute;
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 10px solid #000000;
  content: "";
  bottom: -11px;
  right: 10px;
}

#tooltip {
  position: absolute;
  z-index: 99999;
  flex-grow: 0;
  visibility: hidden;
  line-height: 1.5;
  flex-direction: row;
  justify-content: flex-start;
  align-items: flex-start;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 5px;
  background-color: #f8f9fb;
  color: #000;
}

.middle {
  background-color: red;
  position: absolute;
  width: 273px;
  height: 264px;
  border-radius: 50%;
  top: 58px;
  left: 132px;
}

HMTL :

    <div #PieID class="pieID pie">

  <div *ngFor="let item of cryptoArray;let i=index" (mouseleave)="tooltipRemove(i)" [id]="'slice'+i"
    (mousemove)="coordinates($event,item,color[i],i)" [class]="'slice '+ 's-'+i"
    [ngStyle]="{'transform': 'rotate(' + item.percent  + 'deg) translate3d(0,0,0)'}">

    <div [id]="'s-'+i" class="slice-content" data-content="Something is happening"
      [ngStyle]="{'transform': 'rotate(' +  item.offset  + 'deg) translate3d(0,0,0)' ,'background-color':color[i] }">
    </div>

  </div>

</div>


<div id="tooltip">
  <div>{{tooltipName}}</div>
  <div>{{tooltipValue}} USD</div>
</div>

TS :

  cryptoArray: ChartModel[] = [
    {
      name: "ETH",
      value: 400
    },
    {
      name: "ETH",
      value: 500
    },
    {
      name: "ETH",
      value: 300
    },
    {
      name: 'ETH',
      value: 700
    },
    {
      name: 'XRP',
      value: 200
    },
    {
      name: 'ADA',
      value: 200
    },
    {
      name: 'BNB',
      value: 1000
    }
  ];

  color = [
    "cornflowerblue",
    "olivedrab",
    "orange",
    "tomato",
    "crimson",
    "purple",
    "turquoise",
    "forestgreen",
    "navy",
    "gray"
  ];

  tooltipName: string;
  tooltipValue: number;
  constructor() { }
  ngAfterViewInit(): void {
    this.drawChart();
  }

  ngOnInit(): void {
    // this.cryptoArray = this.calculatePercent(this.cryptoArray);
  }

  coordinates(
    event: MouseEvent,
    item: ChartModel,
    color: string,
    index: number
  ): void {
    // let pixelData = canvas.getContext('2d').getImageData(event.offsetX, event.offsetY, 1, 1).data;
    let canvas = document.createElement('canvas');
    let context = canvas.getContext('2d');
    let myData = context.getImageData(event.offsetX, event.offsetY, 1, 1).data;
    console.log(myData)
    this.tooltipName = item.name;
    this.tooltipValue = item.value;
    const slice = document.getElementById("slice" + index);
    slice.style.visibility = "visible";
    slice.style.setProperty("--visible-width", "166px");
    slice.style.setProperty("--visible-height", "166px");
    slice.style.zIndex = "2";
    this.tooltip(item.name, event.clientX, event.clientY, color);
  }

  tooltip(title: string, x: number, y: number, color: string): void {
    const item = document.getElementById("tooltip");
    item.style.visibility = "visible";
    item.style.top = y + "px";
    item.style.left = x + "px";
    item.style.backgroundColor = color;
  }

  tooltipRemove(index: number): void {
    let item = document.getElementById("tooltip");
    item.style.visibility = "hidden";

    const slice = document.getElementById("slice" + index);
    slice.style.setProperty("--visible-width", "171px");
    slice.style.setProperty("--visible-height", "171px");
    slice.style.strokeWidth = "3";
    slice.style.zIndex = "0";
  }

  public findTotalValue(valueArray: ChartModel[]): number {
    let listTotal = 0;
    // tslint:disable-next-line:prefer-for-of
    for (let i = 0; i < valueArray.length; i++) {
      listTotal += valueArray[i].value;
    }
    return listTotal;
  }

  // tslint:disable-next-line:typedef
  public drawChart() {
    let percent = 0;
    let offset = 0;
    const total = this.findTotalValue(this.cryptoArray);
    this.cryptoArray.forEach((element, i) => {
      // percent = (element.value / total) * 360;
      percent = this.sliceSize(element.value, total);
      // element.percent = percent;
      const itrationInfo = this.itrationSlice(percent, offset);
      element.percent = itrationInfo.offset;
      element.offset = itrationInfo.sizeRotation;
      offset += percent;
      const slice = document.getElementById("slice" + i);
      slice.style.visibility = "visible";
      slice.style.setProperty("--visible-width", "171px");
      slice.style.setProperty("--visible-height", "171px");
    });
  }

  public itrationSlice(sliceSize, offset): any {
    const maxSize = 179;

    if (sliceSize <= maxSize) {
      return this.addSlice(offset, sliceSize);
    } else {
      return this.addSlice(offset, maxSize);
    }
  }

  public addSlice(offset, sliceSize): any {
    const offsett = offset - 1;
    const sizeRotation = -179 + sliceSize;
    return { offset: offsett, sizeRotation };
  }

  public sliceSize(dataNum, dataTotal): number {
    return (dataNum / dataTotal) * 360;
  }
}

whats the problem ? how can i solve this problem ???

1 Answers

i don't know how to fix it but i know why it's happening. the problem is that the slice shapes arn't real shapes like they apear to be. they are actually rectangles. so when you try to hover over one slice, you actually hover over anothr one.

add to the coordinates function this line:

slice.style.backgroundColor = color;

and to tooltipRemove this line:

slice.style.backgroundColor = 'transparent';

and you will see the problem at work.

you have to find a way to make the slices to be like they appear maybe with SVG.

Related