Phi*_*hil 78 javascript html5 html5-canvas
我和n00b一起HTML5工作,我正在使用它canvas来渲染形状,颜色和文字.在我的应用程序中,我有一个视图适配器,动态创建一个画布,并用内容填充它.除了我的文本呈现非常模糊/模糊/拉伸之外,这非常有效.我已经看到了很多,为什么定义其他职位的宽度和高度在CSS会引起这个问题,但我确定这一切javascript.
相关代码(查看小提琴):
HTML
<div id="layout-content"></div>
Run Code Online (Sandbox Code Playgroud)
使用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);
Run Code Online (Sandbox Code Playgroud)
我看到的结果(在Safari中)比在小提琴中显示的更加偏斜:
矿

小提琴

我做错了什么?我是否需要为每个文本元素使用单独的画布?是字体吗?我是否需要首先在HTML5布局中定义画布?有拼写错误吗?我搞不清楚了.
MyN*_*sKo 135
canvas元素独立于设备或监视器的像素比运行.
在iPad 3+上,此比率为2.这实际上意味着您的1000px宽度画布现在需要填充2000px以匹配iPad显示屏上的规定宽度.对我们来说幸运的是,这是由浏览器自动完成的.另一方面,这也是为什么你看到更少的图像和画布元素定义直接适合其可见区域的原因.因为你的画布只知道如何填充1000px但是要求绘制到2000px,浏览器现在必须智能地填充像素之间的空白以显示元素的适当大小.
我强烈建议您阅读HTML5Rocks中的这篇文章,它更详细地解释了如何创建高清元素.
TL;博士?这是一个示例(基于上面的tut),我在自己的项目中使用以适当的分辨率吐出画布:
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);
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!
Phi*_*hil 25
解决了!
我决定看看我设置的更改宽度和高度属性的内容javascript,看看它是如何影响画布大小的 - 而事实并非如此.它会改变分辨率.
为了获得我想要的结果,我还必须设置canvas.style.width属性,这会改变以下物理大小canvas:
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
Run Code Online (Sandbox Code Playgroud)
这 100% 为我解决了这个问题:
var canvas = document.getElementById('canvas');
canvas.width = canvas.getBoundingClientRect().width;
canvas.height = canvas.getBoundingClientRect().height;
Run Code Online (Sandbox Code Playgroud)
(它接近 Adam Ma?kowski 的解决方案)。
我注意到其他答案中没有提到的一个细节。画布分辨率截断为整数值。
默认画布分辨率尺寸为canvas.width: 300和canvas.height: 150。
在我的屏幕上,window.devicePixelRatio: 1.75.
因此,当我设置canvas.height = 1.75 * 150该值时,该值将从所需的值截断262.5为262。
解决方案是选择给定的 CSS 布局尺寸window.devicePixelRatio,以便在缩放分辨率时不会发生截断。
例如,我可以使用width: 300pxandheight: 152px乘以 时会产生整数1.75。
编辑:另一个解决方案是利用 CSS 像素可以是小数这一事实来抵消缩放画布像素的截断。
下面是使用此策略的演示。
编辑:这里是OP的小提琴更新为使用此策略:http://jsfiddle.net/65maD/83/。
main();
// Rerun on window resize.
window.addEventListener('resize', main);
function main() {
// Prepare canvas with properly scaled dimensions.
scaleCanvas();
// Test scaling calculations by rendering some text.
testRender();
}
function scaleCanvas() {
const container = document.querySelector('#container');
const canvas = document.querySelector('#canvas');
// Get desired dimensions for canvas from container.
let {width, height} = container.getBoundingClientRect();
// Get pixel ratio.
const dpr = window.devicePixelRatio;
// (Optional) Report the dpr.
document.querySelector('#dpr').innerHTML = dpr.toFixed(4);
// Size the canvas a bit bigger than desired.
// Use exaggeration = 0 in real code.
const exaggeration = 20;
width = Math.ceil (width * dpr + exaggeration);
height = Math.ceil (height * dpr + exaggeration);
// Set the canvas resolution dimensions (integer values).
canvas.width = width;
canvas.height = height;
/*-----------------------------------------------------------
- KEY STEP -
Set the canvas layout dimensions with respect to the canvas
resolution dimensions. (Not necessarily integer values!)
-----------------------------------------------------------*/
canvas.style.width = `${width / dpr}px`;
canvas.style.height = `${height / dpr}px`;
// Adjust canvas coordinates to use CSS pixel coordinates.
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);
}
function testRender() {
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
// fontBaseline is the location of the baseline of the serif font
// written as a fraction of line-height and calculated from the top
// of the line downwards. (Measured by trial and error.)
const fontBaseline = 0.83;
// Start at the top of the box.
let baseline = 0;
// 50px font text
ctx.font = `50px serif`;
ctx.fillText("Hello World", 0, baseline + fontBaseline * 50);
baseline += 50;
// 25px font text
ctx.font = `25px serif`;
ctx.fillText("Hello World", 0, baseline + fontBaseline * 25);
baseline += 25;
// 12.5px font text
ctx.font = `12.5px serif`;
ctx.fillText("Hello World", 0, baseline + fontBaseline * 12.5);
}Run Code Online (Sandbox Code Playgroud)
/* HTML is red */
#container
{
background-color: red;
position: relative;
/* Setting a border will mess up scaling calculations. */
/* Hide canvas overflow (if any) in real code. */
/* overflow: hidden; */
}
/* Canvas is green */
#canvas
{
background-color: rgba(0,255,0,.8);
animation: 2s ease-in-out infinite alternate both comparison;
}
/* animate to compare HTML and Canvas renderings */
@keyframes comparison
{
33% {opacity:1; transform: translate(0,0);}
100% {opacity:.7; transform: translate(7.5%,15%);}
}
/* hover to pause */
#canvas:hover, #container:hover > #canvas
{
animation-play-state: paused;
}
/* click to translate Canvas by (1px, 1px) */
#canvas:active
{
transform: translate(1px,1px) !important;
animation: none;
}
/* HTML text */
.text
{
position: absolute;
color: white;
}
.text:nth-child(1)
{
top: 0px;
font-size: 50px;
line-height: 50px;
}
.text:nth-child(2)
{
top: 50px;
font-size: 25px;
line-height: 25px;
}
.text:nth-child(3)
{
top: 75px;
font-size: 12.5px;
line-height: 12.5px;
}Run Code Online (Sandbox Code Playgroud)
<!-- Make the desired dimensions strange to guarantee truncation. -->
<div id="container" style="width: 313.235px; height: 157.122px">
<!-- Render text in HTML. -->
<div class="text">Hello World</div>
<div class="text">Hello World</div>
<div class="text">Hello World</div>
<!-- Render text in Canvas. -->
<canvas id="canvas"></canvas>
</div>
<!-- Interaction instructions. -->
<p>Hover to pause the animation.<br>
Click to translate the green box by (1px, 1px).</p>
<!-- Color key. -->
<p><em style="color:red">red</em> = HTML rendered<br>
<em style="color:green">green</em> = Canvas rendered</p>
<!-- Report pixel ratio. -->
<p>Device pixel ratio: <code id="dpr"></code>
<em>(physical pixels per CSS pixel)</em></p>
<!-- Info. -->
<p>Zoom your browser to re-run the scaling calculations.
(<code>Ctrl+</code> or <code>Ctrl-</code>)</p>Run Code Online (Sandbox Code Playgroud)
虽然@MyNameIsKo 的答案仍然有效,但它在 2020 年现在有点过时了,可以改进:
function createHiPPICanvas(w, h) {
let ratio = window.devicePixelRatio;
let cv = document.createElement("canvas");
cv.width = w * ratio;
cv.height = h * ratio;
cv.style.width = w + "px";
cv.style.height = h + "px";
cv.getContext("2d").scale(ratio, ratio);
return cv;
}
Run Code Online (Sandbox Code Playgroud)
总的来说,我们做了以下改进:
backingStorePixelRatio引用,因为这些引用并没有在任何浏览器中以任何重要的方式真正实现(实际上,只有 Safari 返回除 之外的其他内容undefined,并且该版本在 Safari 中仍然可以完美运行);window.devicePixelRatio,它具有出色的支持|| 1 fallback on window.devicePixelRatio, as it is pointless: all browsers that don't support this property don't support .setTransform or .scale either, so this function won't work on them, fallback or not;.setTransform by .scale, as passing in a width and height is a little more intuitive than passing in a transformation matrix.createHiDPICanvas to createHiPPICanvas. As @MyNameIsKo themselves mention in their answer's comments, DPI (Dots per Inch) is printing terminology (as printers make up images out of tiny dots of coloured ink). While similar, monitors display images using pixels, and as such PPI (Pixels per Inch) is a better acronym for our use case.One large benefit of these simplifications is that this answer can now be used in TypeScript without // @ts-ignore (as TS doesn't have types for backingStorePixelRatio).
我通过CSS调整画布元素的大小,以获取父元素的整个宽度。我注意到元素的宽度和高度没有缩放。我一直在寻找设置尺寸的最佳方法。
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
Run Code Online (Sandbox Code Playgroud)
无论您使用哪种屏幕,都可以通过这种简单的方式完美设置画布。
| 归档时间: |
|
| 查看次数: |
66516 次 |
| 最近记录: |