JavaScript高級程序設計(第三版) 第15章 Canvas

Menu

第15章 使用 Canvas 繪圖

15.1 基本用法
15.2 2D 上下文
  • 15.2.1 填充和描邊
  • 15.2.2 繪制矩形
  • 15.2.3 繪制路徑
  • 15.2.4 繪制文本
  • 15.2.5 變換
  • 15.2.6 繪制圖像
  • 15.2.7 陰影
  • 15.2.8 漸變
  • 15.2.9 模式
  • 15.2.10 使用圖像數據
  • 15.2.11 合成

15.1 基本用法
  1. HTML里添加<canvas>元素:接著必須先設置其 width 和 height 屬性,指定可以繪圖的區域大小。出現在開始和結束標簽中的內容是后備信息,如果瀏覽器不支持<canvas>元素,就會顯示這些信息。下面就是<canvas>元素的例子。
<canvas id="drawing" width=" 200" height="200">A drawing of something.</canvas>
  1. 取得繪圖上下文:要在這塊畫布(canvas)上繪圖,需要取得繪圖上下文。而取得繪圖上下文對象的引用,需要調用getContext()方法并傳入上下文的名字。傳入"2d",就可以取得 2D 上下文對象。
var drawing = document.getElementById("drawing");
// 取得 2D 上下文對象
var context = drawing.getContext("2d");  
  1. 導出在<canvas>元素上繪制的圖像:使用 toDataURL()方法,這個方法接受一個參數,即圖像的 MIME

類型格式,而且適合用于創建圖像的任何上下文。默認情況下,瀏覽器會將圖像編碼為 PNG 格式(除非另行指定

)。比如,要取得畫布中的一幅 PNG 格式的圖像。:

var drawing = document.getElementById("drawing");
//取得圖像的數據 URI
var imgURI = drawing.toDataURL("image/png");
//顯示圖像
var image = document.createElement("img");
image.src = imgURI;
document.body.appendChild(image);

15.2 2D 上下文
  • 2D 上下文的坐標開始于<canvas>元素的左上角,原點坐標是(0,0)。

  • 15.2.1 填充和描邊
  • 2D 上下文的兩種基本繪圖操作是填充和描邊。填充,就是用指定的樣式(顏色、漸變或圖像)填
    充圖形;描邊,就是只在圖形的邊緣畫線。操作的結果取決于兩個屬性: fillStyle 和 strokeStyle。
  • 這兩個屬性的值可以是字符串、漸變對象或模式對象,而且它們的默認值都是"#000000"。如果為它們指定表示顏色的字符串值,可以使用 CSS 中指定顏色值的任何格式,包括顏色名、十六進制碼、rgb、 rgba、 hsl 或 hsla。舉個例子:
var drawing = document.getElementById("drawing");
var context = drawing.getContext("2d");
// 所有涉及描邊和填充的操作都將使用這兩個樣式,填充和描邊的顏色需要寫在位置前面;
context.strokeStyle = "red";
context.fillStyle = "#0000ff"

  • 15.2.2 繪制矩形

  • 矩形是唯一一種可以直接在 2D 上下文中繪制的形狀。與矩形有關的方法包括 fillRect()、strokeRect()和 clearRect()。這三個方法都能接收 4 個參數:矩形的 x 坐標、矩形的 y 坐標、矩形寬度和矩形高度。這些參數的單位都是像素。

    • fillRect():方法在畫布上繪制的矩形,默認填充黑色;
    • fillStyle:屬性指定填充的顏色。可以使用 CSS 中指定顏色值的任何格式,包括顏色名、十六進制碼、rgb、 rgba、 hsl 或 hsla。
//繪制紅色矩形
context.fillStyle = "#ff0000";
// (x, y, width, height)
context.fillRect(10, 10, 50, 50);  
//繪制半透明的藍色矩形
context.fillStyle = "rgba(0,0,255,0.5)";
context.fillRect(30, 30, 50, 50);
  • strokeStyle屬性:描邊顏色通過 strokeStyle 屬性指定。
  • strokeRect()方法:方法在畫布上繪制的矩形描邊,默認填充黑色;
  • lineWidth屬性:描邊線條的寬度由 lineWidth 屬性控制,該屬性的值可以是任意整數;
  • lineCap 屬性:可以控制線條末端的形狀是平頭、圓頭還是方頭("butt"、"round"或"square"),
  • lineJoin 屬性:可以控制線條相交的方式是圓交、斜交還是斜接("round"、 "bevel"或"miter")。
//繪制紅色描邊矩形
context.strokeStyle = "#ff0000";
context.strokeRect(10, 10, 50, 50);
//繪制半透明的藍色描邊矩形
context.strokeStyle = "rgba(0,0,255,0.5)";
context.strokeRect(30, 30, 50, 50);
// 以上代碼繪制了兩個重疊的矩形。不過,這兩個矩形都只有框線,內部并沒有填充顏色
  • clearRect()方法:用于清除畫布上的矩形區域。這個方法可以把繪制上下文中的某一矩形區域變透明。
ctx.fillRect(0, 0, 100, 100);
ctx.clearRect(30, 30, 40, 40)

以上code效果

  • 15.2.3 繪制路徑
  • beginPath()方法:開始繪制新路徑。
  • arc(x, y, radius, startAngle, endAngle, counterclockwise):繪制圓形;參數如下:
    • x:圓弧中心(圓心)的 x 軸坐標。
    • y:圓弧中心(圓心)的 y 軸坐標。
    • radius:圓弧的半徑。
    • startAngle:圓弧的起始點, x軸方向開始計算,單位以弧度表示。
    • endAngle:圓弧的終點, 單位以弧度表示。(0, 2*Math.PI 表示畫整個圓)
    • anticlockwise :可選的Boolean值 ,如果為 true,逆時針繪制圓弧,反之,順時針繪制。
canvas = document.getElementById("drawing");
context = canvas.getContext("2d"); // 得到畫圖板對象; ?
context.beginPath();  // 創建新路徑;
context.strokeStyle = "rgba(255,0,255,0.66)";
context.lineWidth = 3;
context.arc(250, 250, 100, 2*Math.PI, false);   //  弧度方法;
context.stroke();
  • lineTo(x, y):從上一點開始繪制一條直線,到(x,y)為止。
context.moveTo(250,250);
context.lineTo(250,160);
context.stroke();
  • moveTo(x, y):將繪圖游標移動到(x,y),不畫線。
  • arcTo(x1, y1, x2, y2, radius):從上一點開始繪制一條弧線,到(x2,y2)為止,并且以給定的半徑 radius 穿過(x1,y1)。(是 Canvas 2D API 根據控制點和半徑繪制圓弧路徑,使用當前的描點(前一個moveTo或lineTo等函數的止點)。根據當前描點與給定的控制點1連接的直線,和控制點1與控制點2連接的直線,作為使用指定半徑的圓的切線,畫出兩條切線之間的弧線路徑。)
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):貝塞爾曲線, 從上一點開始繪制一條曲線,到(x,y)為止,并且以(c1x,c1y)和(c2x,c2y)為控制點。
var c=document.getElementById("drawing");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(50,250);
ctx.bezierCurveTo(200,150,300,350,450,250);
        
// cp1x     第一個貝塞爾控制點的 +


x 坐標
// cp1y     第一個貝塞爾控制點的 y 坐標
// cp2x     第二個貝塞爾控制點的 x 坐標
// cp2y     第二個貝塞爾控制點的 y 坐標
// x    結束點的 x 坐標
// y    結束點的 y 坐標
  • quadraticCurveTo(cx, cy, x, y):從上一點開始繪制一條二次曲線,到(x,y)為止,并且以(cx,cy)作為控制點。
canvas = document.getElementById("myCanvas");
context = canvas.getContext("2d");  // 創建canvas的執行環境;
context.beginPath();  // 創建畫圖路徑;
context.moveTo(50,250);
context.quadraticCurveTo(250, 450,450, 250);  // 一個控制點的線;
context.stroke()   // 筆畫描邊;
  • rect(x, y, width, height):從點(x,y)開始繪制一個矩形,寬度和高度分別由 width 和height 指定。這個方法繪制的是矩形路徑,而不是 strokeRect()和 fillRect()所繪制的獨立的形狀。
context.beginPath();  // 創建畫圖路徑;
context.rect(50,50,100,65);
context.stroke()   // 筆畫描邊;
  • closePath():繪制一條連接到路徑起點的線條;
context.beginPath();  // 創建畫圖路徑;
context.moveTo(50,250);
context.quadraticCurveTo(250, 450,450, 250);  // 一個控制點的線;
context.closePath();
context.stroke();  // 筆畫描邊;
closePath()效果
  • fill():用 fillStyle 填充路徑。
  • stroke():用strokeStyle描邊路徑。
  • clip() 方法從原始畫布中剪切任意形狀和尺寸。一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切的區域內(不能訪問畫布上的其他區域)。您也可以在使用 clip() 方法前通過使用 save() 方法對當前畫布區域進行保存,并在以后的任意時間對其進行恢復(通過 restore() 方法)。
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// 剪切矩形區域
ctx.rect(50,20,200,120);
ctx.stroke();
ctx.clip();
// 在 clip() 之后繪制綠色矩形
ctx.fillStyle="green";
ctx.fillRect(0,0,150,100);
不使用clip
使用clip

  • 15.2.4 繪制文本
  • 繪制文本主要有兩個方法: fillText()strokeText()。這兩個方法都可以接收 4 個參數:要繪制的文本字符串、 x 坐標、 y 坐標和可選的最大像素寬度。
    • 第四個參數表示字符的最大寬度限制:傳入的字符串大于最大寬度,則繪制的文本字符的高度正確,但寬度會收縮以適應最大寬度。
  • font屬性:表示文本樣式、大小及字體,用 CSS 中指定字體的格式來指定,例如"10px Arial"。
  • textAlign屬性:表示文本對齊方式。可能的有"start"、"end"、"left"、"right"和"center"。建議使用"start"和"end",不要使用"left"和"right",因為前兩者的意思更穩妥,能同時適合從左到右和從右到左顯示(閱讀)的語言。
  • textBaseline屬性:表示文本的基線。可能的值有"top"、"hanging"、"middle"、"alphabetic"、"ideographic"和"bottom"。
    • alphabetic:默認。文本基線是普通的字母基線。
    • top:文本基線是 em 方框的頂端。。
    • hanging:文本基線是懸掛基線。
    • middle:文本基線是 em 方框的正中。
    • ideographic:文本基線是表意基線。
    • bottom:文本基線是 em 方框的底端。
textBaseline

  • **Context.measureText() **
  • 方法返回一個 TextMetrics 對象,包含關于文本尺寸的信息(例如文本的寬度)。
var text = ctx.measureText("foo"); // TextMetrics object
text.width; // 16;
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    fontsize = 150;
    ctx.font = fontsize + "px Arial";
    while(ctx.measureText("Hello world!").width > 500){

        fontsize-- ;
        ctx.font = fontsize + "px Arial";

    }
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.translate(250, 250);
    ctx.rotate(90 * Math.PI / 180);
    ctx.scale(0.5, 0.5);
    ctx.fillText("Hello World", 10 , 10);

  • 15.2.5 變換
  • rotate(angle):圍繞原點旋轉圖像 angle 弧度;要移動圓點, 使用下面的translate(x, y)方法;
    • 怎樣實現原地旋轉:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "pink";
ctx.fillRect(100,100,100,100)
var deg = Math.PI/180;  //deg = 1°
ctx.translate(150, 150);      //把原點點從零移到正方形的中心點
ctx.rotate(45*deg);    //繞著原點旋轉45度(即繞著圖像中心點旋轉45度), 下面的transform也是同樣作用
// transfrom要實現旋轉,需要設置前4個參數
// ctx.transform(Math.cos(45*deg),Math.sin(45*deg),-Math.sin(45*deg),Math.cos(45*deg),0,0);
ctx.fillStyle = "blue";
ctx.fillRect(-50,-50,100,100) //旋轉后的圖像坐標需要從新的圓點回到原來的坐標, 即-width, -height

  • translate(x, y):將坐標原點移動到(x,y)。執行這個變換之后, 坐標(0,0)會變成之前由(x,y)表示的點。
ctx.font =  "150px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.translate(250, 250);
ctx.rotate(90 * Math.PI / 180);
ctx.fillText("Hello World", 10 , 10);
  • scale(scaleX, scaleY):縮放圖像,在 x 方向乘以 scaleX,在 y 方向乘以 scaleY。 scaleX和 scaleY 的默認值都是 1.0。
ctx.scale(0.5, 0.5);
ctx.fillText("Hello World", 10 , 10);
  • transform(a, b, c, d, e, f):直接修改變換矩陣。
    • 默認參數:transfrom(1, 0, 0, 1, 0, 0)
      a 水平縮放繪圖
      b 水平傾斜繪圖
      c 垂直傾斜繪圖
      d 垂直縮放繪圖
      e 水平移動繪圖
      f 垂直移動繪圖

  • 15.2.6 繪制圖像

  • context.drawImage()

  • 要加入事件才能在畫布里顯示出圖片

    • <img onload="somefunc(event)" src="image.jpg" id="myImg">
  • 如果你想把一幅圖像繪制到畫布上,可以使用 drawImage()方法。根據期望的最終結果不同,調用這個方法時,可以使用三種不同的參數組合。

    1. 傳入一個 HTML <img>Element,以及繪制該圖像的起點的 x 和 y 坐標.
    • context.drawImage(image, 10, 10);
    1. 如果你想改變繪制后圖像的大小,可以再多傳入兩個參數,分別表示目標寬度和目標高度。
    • context.drawImage(image, 50, 10, 20, 30);
    1. 還可以選擇把圖像中的某個區域繪制到上下文中。 drawImage()方法的這種調
      用方式總共需要傳入 9 個參數:
      要繪制的圖像、
      源圖像的 x 坐標、源圖像的 y 坐標、
      源圖像的寬度、源圖像的高度、
      目標圖像的 x 坐標、目標圖像的 y 坐標、
      目標圖像的寬度、目標圖像的高度。
    • context.drawImage(圖片obj, 源圖片x,源圖片y, x開始切的寬度,x開始切的高度,畫布x點,畫布y點,畫布圖片的寬度,畫布圖片的高度)
  • 除了給 drawImage()方法傳入 HTML <img>元素外,還可以傳入另一個<canvas>元素作為其第一個參數。這樣,就可以把另一個畫布內容繪制到當前畫布上。

  • 獲得圖片修改后的結果:re = canvas.toDataURL(),可以把結果再放回到img元素里;img.src = re;

  • 即圖像不能來自其他域。如果圖像來自其他域,調用toDataURL()會拋出一個錯誤。

  • 15.2.7 陰影

  • 2D 上下文會根據以下幾個屬性的值,自動為形狀或路徑繪制出陰影。

context.shadowColor = "rgba(0,0,255,0.1)";  // 陰影顏色,不設置默認黑色和透明度 不透明是1
context.shadowOffsetX = -100;   // x 軸方向的陰影偏移量 默認0
context.shadowOffsetY = 1;   // y 軸方向的陰影偏移量 默認0
context.shadowBlur = 20;       // 模糊的像素數,默認 0,即不模糊
context.drawImage(img,50,50,200,150)

  • 15.2.8 漸變
    1. 可以調用 createLinearGradient()方法。這個方法接收 4 個參數:起點的 x 坐標、起點的 y 坐標、終點的 x 坐標、終點的 y 坐標。
    2. 下一步就是使用 addColorStop()方法來指定色標。這個方法接收兩個參數:色標位置和 CSS 顏色值。色標位置是一個 0(開始的顏色)到 1(結束的顏色)之間的數字。
    3. 然后就可以把 fillStyle 或 strokeStyle 設置為這個對象,從而使用漸變來繪制形狀或描邊.
var gradient = context.createLinearGradient(30, 30, 80, 80);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//繪制漸變矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);
  1. 放射漸變
  • var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
  • 前三個參數指定的是起點圓的原心(x 和 y)及半徑,后三個參數指定的是終點圓的原心(x 和 y)及半徑。可以把徑向漸變想象成一個長圓桶,而這 6 個參數定義的正是這個桶的兩個圓形開口的位置。如果把一個圓形開口定義得比另一個小一些,那這個圓桶就變成了圓錐體,而通過移動每個圓形開口的位置,就可達到像旋轉這個圓錐體一樣的效果。
var gradient = context.createRadialGradient(55, 55, 10, 55, 55, 30);
gradient.addColorStop(0, "white");
gradient.addColorStop(1, "black");
//繪制漸變矩形
context.fillStyle = gradient;
context.fillRect(30, 30, 50, 50);

  • 15.2.9 模式
  • 模 式 其 實 就 是 重 復 的 圖 像 , 可 以 用 來 填 充 或 描 邊 圖 形 。
  • 要 創 建 一 個 新 模 式 , 可 以 調 用createPattern()方法。
  • 有2個參數:1.imgElement 2.repeat方式: 包括"repeat"、 "repeat-x"、"repeat-y"和"no-repeat"。
img = document.getElementById("myImg");
canvasB = document.getElementById("myCanvasB");
contextB = canvasB.getContext("2d");
// 獲取圖像,把圖像縮小到100x100像素;
contextB.drawImage(img, 0,0,100,100);

canvasA = document.getElementById("myCanvasA");
contextA = canvasA.getContext("2d");
// convasA的Context里創建Pattern,放縮小了的canvasB畫布和repeat模式
pattern = contextA.createPattern(canvasB,"repeat");
// 填充規則
contextA.fillStyle = pattern;
contextA.fillRect(0,0,500,500)
}
  • createPattern()方法的第一個參數也可以是一個<video>元素,或者另一個<canvas>元素。

  • 15.2.10 使用圖像數據
img = document.getElementById("myImg");
var c=document.getElementById("drawing");
var ctx=c.getContext("2d");
// img放到畫布里;
ctx.drawImage(img,0,0,500,500);
// 取得圖像數據
imgData = ctx.getImageData(0,0,c.width,c.height);
// 每個 ImageData 對象都有三個屬性: width、 height 和data。
// 在imgData.data數組中,存著每一個像素點的rgba的值;
data = imgData.data;
for (let i=0, len=data.length; i<len; i+=4){
    //得到每個像素點的數據
    red = data[i];
    green = data[i+1];
    blue = data[i+2];
    //求得每個像素點rgb的平均值
    var average = Math.floor((red+green+blue)/3);
    //設置顏色值,透明度不變
    data[i] = average;
    data[i+1] = average;
    data[i+2] = average;
}
// 覆蓋原來的imgData.data的值
imgData.data = data;
ctx.putImageData(imgData,0,0);

  • 15.2.11 合成
  • 上下文的屬性:context.globalAlpha 設置透明度 1不透明 0透明 ;
canvas = document.getElementById("drawing");
context = canvas.getContext("2d");
context.globalAlpha = 0.5;    // 設置全局上下文的透明度
context.fillStyle = "red";
context.fillRect(0,0, 300, 150);  // 半透明紅色
context.fillStyle = "blue";
context.fillRect(100,100, 300, 150);  // 半透明藍色
  • globalCompositionOperation屬性 表示后繪制的圖形怎樣與先繪制的圖形結合。這個屬性的值是字符串,可能的值如下。

    • source-over(默認值):后繪制的圖形位于先繪制的圖形上方。
    • source-in:后繪制的圖形與先繪制的圖形重疊的部分可見,兩者其他部分完全透明。
    • source-out:后繪制的圖形與先繪制的圖形不重疊的部分可見,先繪制的圖形完全透明。
    • source-atop:后繪制的圖形與先繪制的圖形重疊的部分可見,先繪制圖形不受影響。
    • destination-over: 后繪制的圖形位于先繪制的圖形下方,只有之前透明像素下的部分才可見。
    • destination-in:后繪制的圖形位于先繪制的圖形下方,兩者不重疊的部分完全透明。
    • destination-out:后繪制的圖形擦除與先繪制的圖形重疊的部分。
    • destination-atop:后繪制的圖形位于先繪制的圖形下方,在兩者不重疊的地方,先繪制的圖形會變透明。
    • lighter:后繪制的圖形與先繪制的圖形重疊部分的值相加,使該部分變亮。
    • copy:后繪制的圖形完全替代與之重疊的先繪制圖形。
    • xor:后繪制的圖形與先繪制的圖形重疊的部分執行“異或”操作。


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • 第15章 使用 Canvas 繪圖 1. 基本用法 (1) 要使用 元素,必須先設置其width和 height ...
    yinxmm閱讀 300評論 0 0
  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作為繪圖引擎。它提供了低...
    ShanJiJi閱讀 1,548評論 0 20
  • ??HTML5 添加的最受歡迎的功能就是 元素。這個元素負責在頁面中設定一個區域,然后就可以通過 JavaScri...
    霜天曉閱讀 3,046評論 0 2
  • 和我在成都的街頭走一走 直到所有的燈都熄滅了也不停留
    Mangoqiu閱讀 178評論 0 0
  • 上午在體育館玩后到森林摩爾覓食,孩子說想吃披薩和蘑菇湯,這個地方很陌生,我就到處轉著找(他們在停車場停車),轉了兩...
    土老冒樂園閱讀 155評論 0 0