我使用Chart.js创建了一个实时投票,并希望用户能够通过选择y轴标签左侧的复选框来选择他们的选项。我无法通过Chart.js找出正确的方法
我的第一次尝试是将输入框放在画布之外,但随着它们的增长,它与动态轮询选项的高度不可靠。这是非常糟糕的,因为条形图的高度将根据有多少选项而变化,因此输入框变得一团糟,因为显示的选项是动态的。
这是我最终要在前端实现的图像。如果用户选择该框,则轮询增长以反映用户选择的选择。
下面发表的是我目前陷入困境的代码。我一直坚持试图解决这个问题很长一段时间了。任何帮助将不胜感激!
import { Component, OnInit } from '@angular/core';
// import { Chart } from 'chart.js';
import * as Ably from 'ably';
import * as Chart from 'chart.js';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable, Subject } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { FirebaseService } from '../services/firebase.service';
@Component({
selector: 'app-vote-chart',
templateUrl: './vote-chart.component.html',
styleUrls: ['./vote-chart.component.scss']
})
export class VoteChartComponent implements OnInit {
// Attributes
ably: any
receiveChanel: any
chart: any
users: any
polls:any = [];
poll:any;
votes:any = [];
labels:any = [];
poll_type:string = "";
constructor(db: AngularFirestore, private firebaseService: FirebaseService) {}
ngOnInit() {
this.firebaseService.getPoll("key").subscribe(res => {
const poll_data:any = res.payload.data();
this.poll = {
id: res.payload.id,
helper_text: poll_data.helper_text,
poll_type: poll_data.poll_type,
scoring_type: poll_data.scoring_type,
user: poll_data.user.id,
choices: []
};
this.poll_type = this.poll.poll_type == 2 ? "Pick One" : "Pick Two";
this.firebaseService.getChoices('key').subscribe(res => {
res.forEach((choice) => {
const choice_data:any = choice.payload.doc.data()
this.poll.choices.push({
id: choice.payload.doc.id,
text: choice_data.text,
votes: choice_data.votes
});
this.votes.push(choice_data.votes);
this.labels.push(choice_data.text);
});
console.log("Poll updated!", this.poll);
});
});
this.ably = new Ably.Realtime("key")
// Attach to channel
this.receiveChanel = this.ably.channels.get('vote-channel12')
// Ably subscription
this.receiveChanel.subscribe("update", (message: any) => {
var canvas = <HTMLCanvasElement> document.getElementById("chartjs-2")
var ctx = canvas.getContext("2d");
this.chart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: this.labels,
datasets: [{
label: this.poll_type,
data: this.votes,
fill: false,
backgroundColor: [
"rgba(255, 99, 132, 0.2)",
"rgba(255, 159, 64, 0.2)",
"rgba(255, 205, 86, 0.2)",
"rgba(75, 192, 192, 0.2)",
"rgba(54, 162, 235, 0.2)",
"rgba(153, 102, 255, 0.2)",
"rgba(201, 203, 207, 0.2)"
],
borderColor: [
"rgb(255, 99, 132)",
"rgb(255, 159, 64)",
"rgb(255, 205, 86)",
"rgb(75, 192, 192)",
"rgb(54, 162, 235)",
"rgb(153, 102, 255)",
"rgb(201, 203, 207)"
],
borderWidth: 1
}]
},
options: {
events: ["touchend", "click", "mouseout"],
onClick: function(e) {
console.log("clicked!", e);
},
tooltips: {
enabled: true
},
title: {
display: true,
text: this.poll_type,
fontSize: 14,
fontColor: '#666'
},
legend: {
display: false
},
maintainAspectRatio: true,
responsive: true,
scales: {
xAxes: [{
ticks: {
beginAtZero: true,
precision: 0
}
}]
}
}
})
console.log("Poll", this.poll);
});
}
}
模板代码,内联样式,使其更容易审查
<div id="chart_and_labels_container" style="min-width:620px !important;">
<div style="float:left; line-height: 175px; display: inline-grid; padding-top: 55px; margin: 0;">
<input type="checkbox" (click)="vote(1)" style="width:57px; height: 30px;"/>
<input type="checkbox" (click)="vote(-1)" style="width:57px; margin-top: 10px; height: 30px;"/>
<input type="checkbox" (click)="vote(-1)" style="width:57px; margin-top: 10px; height: 30px;"/>
</div>
<div id="canvasDiv" style="width: 425px; float:left;">
<canvas id="chartjs-2" ></canvas>
</div>
</div>
**更新**
如果无法在画布中获取输入框,有人可以提供一些建议,以确保输入框与动态选择可靠地对齐吗?即,当您有5个选项时,2个选项的标签文本大小不同。如何以智能可靠的方式将画布外的输入框排成一行?
假设Marc的评论是正确的(这似乎就是这种情况),回答你的“什么是对齐输入的替代解决方案”......
使用display: flex
可以更容易地自动调整复选框之间的大小和/或距离,如果包装画布中条形图的容器的高度始终相同,无论有多少选项。
.chart-container {
display: flex;
}
.chart {
height: 200px;
}
.checkbox-container {
display: flex;
flex-direction: column;
height: 128px; /* height - adjust as needed */
margin-top: 38px; /* positioning - adjust as needed */
background: white; /* demo purpose only - hide image checkboxes */
position: absolute; /* demo purpose only - hide image checkboxes */
left: 10px; /* demo purpose only - hide image checkboxes */
padding: 0 8px; /* demo purpose only - hide image checkboxes */
z-index: 1; /* demo purpose only - hide image checkboxes */
}
.checkbox {
cursor: pointer;
height: 100%;
width: 100%;
min-width: 16px; /* minimum checkbox size - adjust as needed */
}
<!-- 3 bars example -->
<div class="chart-container">
<div class="checkbox-container">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
</div>
<img class="chart" src="https://i.stack.imgur.com/440p0.png">
</div>
<!-- 4 bars examples -->
<div class="chart-container">
<div class="checkbox-container">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
</div>
<img class="chart" src="https://i.stack.imgur.com/440p0.png">
</div>
<!-- 5 bars examples -->
<div class="chart-container">
<div class="checkbox-container">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
</div>
<img class="chart" src="https://i.stack.imgur.com/440p0.png">
</div>
你可以...
position: relative
将画布包装在div容器中position: absolute
为您的复选框创建一个容器position: absolute
容器中并使用margin-bottom
,以便它们与您的图形完美对齐如果选项的数量影响图表栏的高度,则必须使CSS值相应地改变...
document.querySelector('.checkbox').style.height = ...
[style.height.px]="..."
下面是一个使用上面第三个选项的工作示例,CSS类根据checkbox-container
中的复选框/兄弟的数量更改值。
整个想法是保持复选框高度等于图表栏高度,复选框之间的距离等于图表栏距离的距离。
请注意,对齐的所有像素值都相对于您的预期和可以播放,但我想它会给你全局。
希望能帮助到你!
.chart-container {
position: relative;
}
.chart {
height: 200px;
}
.checkbox-container {
background: white; /* for demo purpose - hides image checkboxes */
padding-right: 8px; /* for demo purpose - hides image checkboxes */
position: absolute;
top: 44px; /* adjust as needed */
left: 8px; /* adjust as needed */
}
.checkbox {
display: block;
margin-bottom: 15px; /* adjust as needed */
height: 28px; /* desired checkbox height */
width: 28px; /* desired checkbox width */
cursor: pointer;
}
/* 5 checkboxes */
.checkbox:first-child:nth-last-child(5),
.checkbox:first-child:nth-last-child(5) ~ .checkbox {
margin-bottom: 6px; /* adjust as needed */
height: 18px; /* desired checkbox height */
width: 18px; /* desired checkbox width */
}
<!-- 3 bars example -->
<div class="chart-container">
<img class="chart" src="https://i.stack.imgur.com/440p0.png">
<div class="checkbox-container">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
</div>
</div>
<!-- 5 bars examples - sorry didn't have an image with 5 bars -->
<div class="chart-container">
<img class="chart" src="https://i.stack.imgur.com/440p0.png">
<div class="checkbox-container">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
<input class="checkbox" type="checkbox">
</div>
</div>