私はhtml5キャンバス要素を使用して、ここ内のさまざまなポイントを示すドットでグラフを描画します。
マウスホバーのさまざまなポイントにさまざまなツールヒントを表示したい。ツールヒントとして表示されるテキストは、ユーザーによって提供されます。
グラフのさまざまなポイントにツールチップを追加する方法を試しましたが、理解できませんでした。ドットの表示に使用しているコードは次のとおりです。
// Draw the dots
c.fillStyle = '#333';
for (var i = 0; i < data.values.length; i++) {
c.beginPath();
c.arc(getXPixel(data.values[i].X), getYPixel(data.values[i].Y), 4, 0, Math.PI * 2, true);
c.fill();
}
ユーザー入力をツールチップとして表示できるようにするには、このコードにどのような追加を行う必要がありますか?
ユーザーがチャートのデータドットの上に移動したときにツールチップを表示できます
このツールチップは、リンクされたテキストボックスからテキストを描画し、データドットの上にそれ自体を配置する2番目のキャンバスです。
まず、各データドットのツールチップ情報を保持する配列を作成します。
var dots = [];
ツールチップごとに、次のものが必要です。
これが、ドットで保存されるツールチップ情報を作成するためのコードです[]
// define tooltips for each data point
for(var i = 0; i < data.values.length; i ++) {
dots.Push({
x: getXPixel(data.values[i].X),
y: getYPixel(data.values[i].Y),
r: 4,
rXr: 16,
tip: "#text"+(i+1)
});
}
次に、ドット配列を調べるマウスムーブハンドラーを設定します。ツールヒントは、ユーザーがdata = dot内に移動した場合に表示されます。
// request mousemove events
$("#graph").mousemove(function(e){handleMouseMove(e);});
// show tooltip when mouse hovers over dot
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var hit = false;
for (var i = 0; i < dots.length; i++) {
var dot = dots[i];
var dx = mouseX - dot.x;
var dy = mouseY - dot.y;
if (dx * dx + dy * dy < dot.rXr) {
tipCanvas.style.left = (dot.x) + "px";
tipCanvas.style.top = (dot.y - 40) + "px";
tipCtx.clearRect(0, 0, tipCanvas.width, tipCanvas.height);
tipCtx.fillText($(dot.tip).val(), 5, 15);
hit = true;
}
}
if (!hit) { tipCanvas.style.left = "-200px"; }
}
[コードに合わせて編集]
ここにコードとフィドルがあります: http://jsfiddle.net/m1erickson/yLBjM/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; margin-top:35px; }
#wrapper{position:relative; width:300px; height:150px;}
canvas{border:1px solid red;}
#tip{background-color:white; border:1px solid blue; position:absolute; left:-200px; top:100px;}
</style>
<script>
$(function(){
var graph = document.getElementById("graph");
var ctx = graph.getContext("2d");
var tipCanvas = document.getElementById("tip");
var tipCtx = tipCanvas.getContext("2d");
var canvasOffset = $("#graph").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var graph;
var xPadding = 30;
var yPadding = 30;
// Notice I changed The X values
var data = { values:[
{ X: 0, Y: 12 },
{ X: 2, Y: 28 },
{ X: 3, Y: 18 },
{ X: 4, Y: 34 },
{ X: 5, Y: 40 },
{ X: 6, Y: 80 },
{ X: 7, Y: 80 }
]};
// define tooltips for each data point
var dots = [];
for(var i = 0; i < data.values.length; i ++) {
dots.Push({
x: getXPixel(data.values[i].X),
y: getYPixel(data.values[i].Y),
r: 4,
rXr: 16,
color: "red",
tip: "#text"+(i+1)
});
}
// request mousemove events
$("#graph").mousemove(function(e){handleMouseMove(e);});
// show tooltip when mouse hovers over dot
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var hit = false;
for (var i = 0; i < dots.length; i++) {
var dot = dots[i];
var dx = mouseX - dot.x;
var dy = mouseY - dot.y;
if (dx * dx + dy * dy < dot.rXr) {
tipCanvas.style.left = (dot.x) + "px";
tipCanvas.style.top = (dot.y - 40) + "px";
tipCtx.clearRect(0, 0, tipCanvas.width, tipCanvas.height);
tipCtx.fillText($(dot.tip).val(), 5, 15);
hit = true;
}
}
if (!hit) { tipCanvas.style.left = "-200px"; }
}
//変更されていないコードが続きます
// Returns the max Y value in our data list
function getMaxY() {
var max = 0;
for(var i = 0; i < data.values.length; i ++) {
if(data.values[i].Y > max) {
max = data.values[i].Y;
}
}
max += 10 - max % 10;
return max;
}
// Returns the max X value in our data list
function getMaxX() {
var max = 0;
for(var i = 0; i < data.values.length; i ++) {
if(data.values[i].X > max) {
max = data.values[i].X;
}
}
// omited
//max += 10 - max % 10;
return max;
}
// Return the x pixel for a graph point
function getXPixel(val) {
// uses the getMaxX() function
return ((graph.width - xPadding) / (getMaxX() + 1)) * val + (xPadding * 1.5);
// was
//return ((graph.width - xPadding) / getMaxX()) * val + (xPadding * 1.5);
}
// Return the y pixel for a graph point
function getYPixel(val) {
return graph.height - (((graph.height - yPadding) / getMaxY()) * val) - yPadding;
}
graph = document.getElementById("graph");
var c = graph.getContext('2d');
c.lineWidth = 2;
c.strokeStyle = '#333';
c.font = 'italic 8pt sans-serif';
c.textAlign = "center";
// Draw the axises
c.beginPath();
c.moveTo(xPadding, 0);
c.lineTo(xPadding, graph.height - yPadding);
c.lineTo(graph.width, graph.height - yPadding);
c.stroke();
// Draw the X value texts
var myMaxX = getMaxX();
for(var i = 0; i <= myMaxX; i ++) {
// uses data.values[i].X
c.fillText(i, getXPixel(i), graph.height - yPadding + 20);
}
/* was
for(var i = 0; i < data.values.length; i ++) {
// uses data.values[i].X
c.fillText(data.values[i].X, getXPixel(data.values[i].X), graph.height - yPadding + 20);
}
*/
// Draw the Y value texts
c.textAlign = "right"
c.textBaseline = "middle";
for(var i = 0; i < getMaxY(); i += 10) {
c.fillText(i, xPadding - 10, getYPixel(i));
}
c.strokeStyle = '#f00';
// Draw the line graph
c.beginPath();
c.moveTo(getXPixel(data.values[0].X), getYPixel(data.values[0].Y));
for(var i = 1; i < data.values.length; i ++) {
c.lineTo(getXPixel(data.values[i].X), getYPixel(data.values[i].Y));
}
c.stroke();
// Draw the dots
c.fillStyle = '#333';
for(var i = 0; i < data.values.length; i ++) {
c.beginPath();
c.arc(getXPixel(data.values[i].X), getYPixel(data.values[i].Y), 4, 0, Math.PI * 2, true);
c.fill();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="wrapper">
<canvas id="graph" width=300 height=150></canvas>
<canvas id="tip" width=100 height=25></canvas>
</div>
<br><br>
<input type="text" id="text1" value="text 1"/><br><br>
<input type="text" id="text2" value="text 2"/><br><br>
<input type="text" id="text3" value="text 3"/><br><br>
<input type="text" id="text4" value="text 4"/><br><br>
<input type="text" id="text5" value="text 5"/><br><br>
<input type="text" id="text6" value="text 6"/><br><br>
<input type="text" id="text7" value="text 7"/><br><br>
</body>
</html>
私はmarkEのソリューションを試してみましたが、少し下にスクロールしたとき(たとえば、キャンバスを少し下に置いたとき)を除いて、問題なく機能しました。
そうすると、マウスオーバーが認識される位置が同じ長さの下部に移動し、キャンバスの外側になり、まったく認識されなくなる可能性があります...
.clientXと.clientYの代わりにmouseEvent.pageXとmouseEvent.pageYを使用する場合は、問題ありません。より多くのコンテキストのために、これが私のコードです:
// Filling the dots
var dots = [];
// [...]
dots.Push({
x: xCoord,
y: yCoord,
v: value,
r: 5,
tooltipRadius2: 7*7 // a little increased radius for making it easier to hit
});
// [...]
var tooltipCanvas = $('#tooltipCanvas')[0];
var tooltipCtx = tooltipCanvas.getContext('2d');
var canvasOffset = canvas.offset();
canvas.mousemove(function (e) {
// getting the mouse position relative to the page - not the client
var mouseX = parseInt(e.pageX - canvasOffset.left);
var mouseY = parseInt(e.pageY - canvasOffset.top);
var hit = false;
for (var i = 0; i < dots.length; i++) {
var dot = dots[i];
var dx = mouseX - dot.x;
var dy = mouseY - dot.y;
if (dx * dx + dy * dy < dot.tooltipRadius2) {
// show tooltip to the right and below the cursor
// and moving with it
tooltipCanvas.style.left = (e.pageX + 10) + "px";
tooltipCanvas.style.top = (e.pageY + 10) + "px";
tooltipCtx.clearRect(0, 0, tooltipCanvas.width, tooltipCanvas.height);
tooltipCtx.textAlign = "center";
tooltipCtx.fillText(dot.v, 20, 15);
hit = true;
// when a dot is found, don't keep on searching
break;
}
}
if (!hit) {
tooltipCanvas.style.left = "-200px";
}
});
たぶん、グラフの「タイトル」属性で遊んで、マウスの位置に応じてその内容を適応させることができます。このハンドラをフィドルコードに追加してみてください。
graph.addEventListener("mousemove", (function(evt) {
var rect = evt.target.getBoundingClientRect();
var x = evt.clientX - rect.left;
var y = evt.clientY - rect.top;
var xd, yd;
graph.title = "";
for(var i = 0; i < data.values.length; i ++) {
xd = getXPixel(data.values[i].X);
yd = getYPixel(data.values[i].Y);
if ((x > xd-5) && (x < xd+5) &&(y > yd-5) && (y < yd+5) ) {
graph.title = document.getElementById("text"+(i+1)).value;
break;
}
}
}), false);
ここを参照してください: 更新されたフィドル
編集:上記のコードでは、マウスがポイントの周りの10x10の正方形にある場合、ツールチップを表示することを選択しています。もちろん、これは適合させることができます。さらに、おそらくgetElementByIdの値を呼び出す前に、実行する必要のあるテストがさらにあり、nullを返す可能性があります。
短い答え:今やったように、できません。
長い答え:可能ですが、30ミリ秒ごとなどにマウスの正確な位置を取得する必要があります。ミリ秒ごとに、マウスがドットの上にあるかどうかを確認し、画面を再描画し、その場合はツールチップを表示する必要があります。自分でこれを行うのは面倒な場合があります。そのため、私は gee.js を使用しています。
この例を確認してください: http://jsfiddle.net/Saturnix/Aexw4/
これは、マウスのホバリングを制御する式です。
g.mouseX < x + r && g.mouseX > x -r && g.mouseY > y -r && g.mouseY < y+r