Mercurial > gemma
comparison client/src/components/gauge/Waterlevel.vue @ 2816:c02cebff3f16
client: SPUC7/8: fix tooltip size and positioning
The size is now dynamically calculated based on the content and the tooltip is now
guaranteed to be visible instead of reaching out of the viewport.
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Tue, 26 Mar 2019 19:37:55 +0100 |
parents | 97cf32cf2562 |
children | 53c2bd009c68 |
comparison
equal
deleted
inserted
replaced
2815:12f053763be2 | 2816:c02cebff3f16 |
---|---|
637 .call(brush.move, this.scale.x.range()); | 637 .call(brush.move, this.scale.x.range()); |
638 | 638 |
639 eventRect.call(zoom); | 639 eventRect.call(zoom); |
640 }, | 640 }, |
641 createTooltips(eventRect) { | 641 createTooltips(eventRect) { |
642 let dots = this.diagram.append("g").attr("class", "chart-dots"); | 642 // create clippable container for the dot |
643 dots | 643 this.diagram |
644 .append("g") | |
645 .attr("class", "chart-dots") | |
644 .append("circle") | 646 .append("circle") |
645 .attr("class", "chart-dot") | 647 .attr("class", "chart-dot") |
646 .attr("r", 4); | 648 .attr("r", 4); |
647 let tooltips = this.diagram.append("g").attr("class", "chart-tooltip"); | 649 |
648 tooltips | 650 // create container for the tooltip |
649 .append("rect") | 651 const tooltip = this.diagram.append("g").attr("class", "chart-tooltip"); |
650 .attr("x", -25) | 652 tooltip.append("rect"); |
651 .attr("y", -25) | 653 |
652 .attr("rx", 4) | 654 const padding = 5; |
653 .attr("ry", 4) | 655 |
654 .attr("width", 105) | 656 // create container for multiple text rows |
655 .attr("height", 40); | 657 const tooltipText = tooltip.append("text").attr("text-anchor", "middle"); |
656 let tooltipText = tooltips.append("text"); | 658 tooltipText.append("tspan").attr("alignment-baseline", "hanging"); |
657 tooltipText | 659 tooltipText |
658 .append("tspan") | 660 .append("tspan") |
659 .attr("x", -15) | 661 .attr("dy", 18) |
660 .attr("y", -8); | 662 .attr("alignment-baseline", "hanging"); |
661 tooltipText | |
662 .append("tspan") | |
663 .attr("x", 8) | |
664 .attr("y", 8); | |
665 | 663 |
666 eventRect | 664 eventRect |
667 .on("mouseover", () => { | 665 .on("mouseover", () => { |
668 this.svg.select(".chart-dot").style("opacity", 1); | 666 this.diagram.select(".chart-dot").style("opacity", 1); |
669 this.svg.select(".chart-tooltip").style("opacity", 1); | 667 this.diagram.select(".chart-tooltip").style("opacity", 1); |
670 }) | 668 }) |
671 .on("mouseout", () => { | 669 .on("mouseout", () => { |
672 this.svg.select(".chart-dot").style("opacity", 0); | 670 this.diagram.select(".chart-dot").style("opacity", 0); |
673 this.svg.select(".chart-tooltip").style("opacity", 0); | 671 this.diagram.select(".chart-tooltip").style("opacity", 0); |
674 }) | 672 }) |
675 .on("mousemove", () => { | 673 .on("mousemove", () => { |
676 let x0 = this.scale.x.invert( | 674 // find data point closest to mouse |
675 const x0 = this.scale.x.invert( | |
677 d3.mouse(document.querySelector(".zoom"))[0] | 676 d3.mouse(document.querySelector(".zoom"))[0] |
678 ), | 677 ), |
679 i = d3.bisector(d => d.date).left(this.waterlevels, x0, 1), | 678 i = d3.bisector(d => d.date).left(this.waterlevels, x0, 1), |
680 d0 = this.waterlevels[i - 1], | 679 d0 = this.waterlevels[i - 1], |
681 d1 = this.waterlevels[i] || d0, | 680 d1 = this.waterlevels[i] || d0, |
682 d = x0 - d0.date > d1.date - x0 ? d1 : d0; | 681 d = x0 - d0.date > d1.date - x0 ? d1 : d0; |
683 | 682 |
684 this.svg | 683 const coords = { |
684 x: this.scale.x(d.date), | |
685 y: this.scale.y(d.waterlevel) | |
686 }; | |
687 | |
688 // position the dot | |
689 this.diagram | |
685 .select(".chart-dot") | 690 .select(".chart-dot") |
686 .style("opacity", 1) | 691 .style("opacity", 1) |
687 .attr( | 692 .attr("transform", `translate(${coords.x}, ${coords.y})`); |
688 "transform", | 693 |
689 `translate(${this.scale.x(d.date)}, ${this.scale.y( | 694 // write date |
690 d.waterlevel | 695 this.diagram.select(".chart-tooltip text tspan:first-child").text( |
691 )})` | |
692 ); | |
693 this.svg | |
694 .select(".chart-tooltip") | |
695 .style("opacity", 1) | |
696 .attr( | |
697 "transform", | |
698 `translate(${this.scale.x(d.date) - 25}, ${this.scale.y( | |
699 d.waterlevel | |
700 ) - 25})` | |
701 ); | |
702 this.svg.select(".chart-tooltip text tspan:first-child").text( | |
703 d.date.toLocaleString([], { | 696 d.date.toLocaleString([], { |
704 year: "2-digit", | 697 year: "2-digit", |
705 month: "2-digit", | 698 month: "2-digit", |
706 day: "2-digit", | 699 day: "2-digit", |
707 hour: "2-digit", | 700 hour: "2-digit", |
708 minute: "2-digit" | 701 minute: "2-digit" |
709 }) | 702 }) |
710 ); | 703 ); |
711 this.svg | 704 // write waterlevel |
705 this.diagram | |
712 .select(".chart-tooltip text tspan:last-child") | 706 .select(".chart-tooltip text tspan:last-child") |
713 .text(d.waterlevel + " cm"); | 707 .text(d.waterlevel + " cm"); |
708 | |
709 // get text dimensions | |
710 const textBBox = this.diagram | |
711 .select(".chart-tooltip text") | |
712 .node() | |
713 .getBBox(); | |
714 | |
715 this.diagram | |
716 .selectAll(".chart-tooltip text tspan") | |
717 .attr("x", textBBox.width / 2 + padding) | |
718 .attr("y", padding); | |
719 | |
720 // position and scale tooltip box | |
721 | |
722 let xMax = this.dimensions.width - textBBox.width; | |
723 let tooltipX = Math.min(coords.x - textBBox.width / 2, xMax); | |
724 let tooltipY = coords.y - textBBox.height * 2 + padding * 2; | |
725 this.diagram | |
726 .select(".chart-tooltip") | |
727 .style("opacity", 1) | |
728 .attr("transform", `translate(${tooltipX}, ${tooltipY})`) | |
729 .select("rect") | |
730 .attr("width", textBBox.width + padding * 2) | |
731 .attr("height", textBBox.height + padding * 2); | |
714 }); | 732 }); |
715 }, | 733 }, |
716 isNext(seconds) { | 734 isNext(seconds) { |
717 // helper to check whether points in the chart are "next to each other" | 735 // helper to check whether points in the chart are "next to each other" |
718 // for that they need to be exactly the specified amount of seconds apart. | 736 // for that they need to be exactly the specified amount of seconds apart. |