2013-03-27 615 views
56

私は合計n00bHTML5であり、図形、色、テキストをレンダリングするのにcanvasと一緒に働いています。私のアプリでは、ビューアダプターがあり、キャンバスを動的に作成し、内容で埋めます。これは、私のテキストが非常にぼやけて/ぼやけて/伸びていることを除いて、本当にきれいに動作します。 の幅をの高さをに設定した理由は、この問題の原因になりますが、すべてをjavascriptに定義しています。HTML5キャンバスでぼやけたテキストを修正するにはどうすればよいですか?

関連するコード(ビューFiddle):

HTML

<div id="layout-content"></div> 

Javascriptを

var width = 500;//FIXME:size.w; 
var height = 500;//FIXME:size.h; 

var canvas = document.createElement("canvas"); 
//canvas.className="singleUserCanvas"; 
canvas.width=width; 
canvas.height=height; 
canvas.border = "3px solid #999999"; 
canvas.bgcolor = "#999999"; 
canvas.margin = "(0, 2%, 0, 2%)"; 

var context = canvas.getContext("2d"); 

////////////////// 
//// SHAPES //// 
////////////////// 

var left = 0; 

//draw zone 1 rect 
context.fillStyle = "#8bacbe"; 
context.fillRect(0, (canvas.height*5/6)+1, canvas.width*1.5/8.5, canvas.height*1/6); 

left = left + canvas.width*1.5/8.5; 

//draw zone 2 rect 
context.fillStyle = "#ffe381"; 
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*2.75/8.5, canvas.height*1/6); 

left = left + canvas.width*2.75/8.5 + 1; 

//draw zone 3 rect 
context.fillStyle = "#fbbd36"; 
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*1.25/8.5, canvas.height*1/6); 

left = left + canvas.width*1.25/8.5; 

//draw target zone rect 
context.fillStyle = "#004880"; 
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*0.25/8.5, canvas.height*1/6); 

left = left + canvas.width*0.25/8.5; 

//draw zone 4 rect 
context.fillStyle = "#f8961d"; 
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width*1.25/8.5, canvas.height*1/6); 

left = left + canvas.width*1.25/8.5 + 1; 

//draw zone 5 rect 
context.fillStyle = "#8a1002"; 
context.fillRect(left+1, (canvas.height*5/6)+1, canvas.width-left, canvas.height*1/6); 

//////////////// 
//// TEXT //// 
//////////////// 

//user name 
context.fillStyle = "black"; 
context.font = "bold 18px sans-serif"; 
context.textAlign = 'right'; 
context.fillText("User Name", canvas.width, canvas.height*.05); 

//AT: 
context.font = "bold 12px sans-serif"; 
context.fillText("AT: 140", canvas.width, canvas.height*.1); 

//AB: 
context.fillText("AB: 94", canvas.width, canvas.height*.15); 

//this part is done after the callback from the view adapter, but is relevant here to add the view back into the layout. 
var parent = document.getElementById("layout-content"); 
parent.appendChild(canvas); 

私は(サファリで)見ていた結果ははるかにありますFidに示されているよりも歪んだDLE:

鉱山

Rendered output in Safari

フィドル

Rendered output on JSFiddle

私が間違って何をしているのですか?各テキスト要素に別々のキャンバスが必要ですか?それはフォントですか?最初にキャンバスをHTML5レイアウトで定義する必要がありますか?タイプミスはありますか?迷っています。

+0

あなたは 'clearRect'を呼び出さないようです。 – David

+1

このpolyfillは、自動的にアップスケールされないHiDPIブラウザ(現在のところSafariは唯一のものです)で最も基本的なキャンバス操作を修正します... https://github.com/jondavidjohn/hidpi-canvas-polyfill – jondavidjohn

答えて

97

をcanvas要素は、デバイスまたはモニタのピクセル比から独立して動作します。

iPad 3以降では、この比率は2です。これは、1000px幅のキャンバスが、iPadディスプレイ上の幅に合わせて2000pxを塗りつぶす必要があることを意味します。幸いにも私たちにとっては、これはブラウザによって自動的に行われます。一方、これは、可視領域に直接フィットするように作られた画像やキャンバス要素の定義が少なくなる理由です。あなたのキャンバスは1000pxの塗り方しか知りませんが、2000pxに描画するように求められているため、ブラウザは適切なサイズで要素を表示するためにピクセル間の空白をインテリジェントに埋めなければなりません。

HTML5Rocksからthis articleを読んで、高精細要素の作成方法を詳しく説明してください。

tl; dr?

var PIXEL_RATIO = (function() { 
    var ctx = document.createElement("canvas").getContext("2d"), 
     dpr = window.devicePixelRatio || 1, 
     bsr = ctx.webkitBackingStorePixelRatio || 
       ctx.mozBackingStorePixelRatio || 
       ctx.msBackingStorePixelRatio || 
       ctx.oBackingStorePixelRatio || 
       ctx.backingStorePixelRatio || 1; 

    return dpr/bsr; 
})(); 


createHiDPICanvas = function(w, h, ratio) { 
    if (!ratio) { ratio = PIXEL_RATIO; } 
    var can = document.createElement("canvas"); 
    can.width = w * ratio; 
    can.height = h * ratio; 
    can.style.width = w + "px"; 
    can.style.height = h + "px"; 
    can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0); 
    return can; 
} 

//Create canvas with the device resolution. 
var myCanvas = createHiDPICanvas(500, 250); 

//Create canvas with a custom resolution. 
var myCustomCanvas = createHiDPICanvas(500, 200, 4); 

・ホープ、このことができます:ここに は、私は、適切な解像度でキャンバスを吐き出すために私自身のプロジェクトで使用(上記TUTに基づく)の例です!

+0

これはうまくいった!ご協力いただきありがとうございます。 – Phil

+1

私のcreateHiDPI()メソッドは多少の名前が付けられていないことに言及する価値はあると思っています。 DPIはプリント専用の用語で、PPIはモニタがドットではなくピクセルを使用してイメージを表示するため、より適切な頭字語です。 – MyNameIsKo

+2

この比率は、ページの存続期間中に実際に変化する可能性があることに注意してください。たとえば、Chromeのウィンドウを古い「標準」外部モニタからmacbookの内蔵網膜画面にドラッグすると、コードは異なる比率を計算します。この値をキャッシュする予定の場合は、ちょうどFYIです。 (外見は比1、網膜スクリーン2は好奇心が強い場合) – Aardvark

19

解決済み!そして、それはなかった -

は、私はそれがキャンバスのサイズに影響を与えたかを確認するためにjavascriptに設定高さ属性を変更するかを見ることにしました。解像度が変わります。

私が望んでいた結果を得るために、私もcanvasの物理的なサイズを変更canvas.style.width属性、設定する必要がありました:

canvas.width=1000;//horizontal resolution (?) - increase for better looking text 
canvas.height=500;//vertical resolution (?) - increase for better looking text 
canvas.style.width=width;//actual width of canvas 
canvas.style.height=height;//actual height of canvas 
+1

理想的な結果を得るためには、キャンバスのスタイル属性には一切触れず、キャンバス自体の幅と高さの属性でサイズを制御します。こうすることで、キャンバス上の1つのピクセルが画面上の1つのピクセルに等しいことを確認できます。 – Philipp

+5

私は同意しません。 style.width/height属性を変更するのは、まさにHiDPIキャンバスを作成する方法です。 – MyNameIsKo

+2

あなたの答えでは、canvas.widthを1000に、canvas.style.widthを500に設定しました。これは、ピクセル比率が2のデバイスに対してのみ有効です。デスクトップモニタと同様に、キャンバスは不要なピクセルに描画します。より高い比率では、ぼんやりとした低い資産/要素で出発したところですぐに戻ることができます。フィリップスが指摘していたもう一つの問題は、あなたが文脈に描くものすべてが、その値の半分で表示されているにもかかわらず、あなたの倍増幅/高さに描画されなければならないということです。これに対する修正は、キャンバスのコンテキストを2倍に設定することです。 – MyNameIsKo

2

キャンバス要素のサイズをCSSで変更し、親要素の幅全体を取得します。私は、要素の幅と高さがスケーリングされていないことに気づいた。私はサイズを設定するための最良の方法を探していました。

canvas.width = canvas.clientWidth; 
canvas.height = canvas.clientHeight; 

どのような画面を使用する場合でも、この簡単な方法でキャンバスが完全に設定されます。

1

(SVG to Canvas js library)のコードをMyNameIsKoに少し変更しました。私はしばらく混乱していて、これのために少し時間を費やしました。これは誰か助けて欲しい。

HTML

<div id="chart"><canvas></canvas><svg>Your SVG here</svg></div> 

Javascriptを

window.onload = function() { 

var PIXEL_RATIO = (function() { 
    var ctx = document.createElement("canvas").getContext("2d"), 
     dpr = window.devicePixelRatio || 1, 
     bsr = ctx.webkitBackingStorePixelRatio || 
       ctx.mozBackingStorePixelRatio || 
       ctx.msBackingStorePixelRatio || 
       ctx.oBackingStorePixelRatio || 
       ctx.backingStorePixelRatio || 1; 

    return dpr/bsr; 
})(); 

setHiDPICanvas = function(canvas, w, h, ratio) { 
    if (!ratio) { ratio = PIXEL_RATIO; } 
    var can = canvas; 
    can.width = w * ratio; 
    can.height = h * ratio; 
    can.style.width = w + "px"; 
    can.style.height = h + "px"; 
    can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0); 
} 

var svg = document.querySelector('#chart svg'), 
    canvas = document.querySelector('#chart canvas'); 

var svgSize = svg.getBoundingClientRect(); 
var w = svgSize.width, h = svgSize.height; 
setHiDPICanvas(canvas, w, h); 

var svgString = (new XMLSerializer).serializeToString(svg); 
var ctx = canvas.getContext('2d'); 
ctx.drawSvg(svgString, 0, 0, w, h); 

} 
0

この100%が私のためにそれを解く:

var canvas = document.getElementById('canvas'); 
canvas.width = canvas.getBoundingClientRect().width; 
canvas.height = canvas.getBoundingClientRect().height; 

(それはアダムMańkowskiの解に近いです)。

関連する問題