8_1Canvas

線條樣式

  1. 繪制直線,第五章知識簡單回顧
  • lineWidth 設置或返回當前的線條寬度,單位為像素

  • lineCap 設置或返回線條的結束端點樣式

    • butt 默認。向線條的每個末端添加平直的邊緣。
    • round 向線條的每個末端添加圓形線帽。
    • square 向線條的每個末端添加正方形線帽。
    • "round" 和 "square" 會使線條略微變長。

    cxt.lineCap = "round";

  • lineJoin 設置或返回兩條線相交時,所創建的拐角類型

    • miter 默認。創建尖角。
    • bevel 創建斜角。
    • round 創建圓角。

    cxt.lineJoin = "bevel";

  • miterLimit 設置或返回最大斜接長度。
    斜接長度指的是在兩條線交匯處內角和外角之間的距離。該屬性定義了斜連線長度和線條寬度的最大比率

    • 只有當 lineJoin 屬性為 "miter" 時,miterLimit 才有效。
    • 邊角的角度越小,斜接長度就會越大。為了避免斜接長度過長,我們可以使用 miterLimit 屬性。
    • 如果斜接長度超過 miterLimit 的值,邊角會以 lineJoin 的 "bevel" 類型來顯示
    cxt.lineJoin = "miter";
    cxt.miterLimit=2;
    

矩形

  1. rect(x,y,w,h) 創建矩形。
  • fillRect(x,y,w,h) 繪制"被填充"的矩形。
  • strokeRect(x,y,w,h) 繪制矩形(無填充)。
  • clearRect(x,y,w,h) 在給定的矩形內清除指定的像素。
cxt.fillRect(100,100,100,100)
cxt.clearRect(110,110,80,80);

路徑方法

  • fill() 填充當前繪圖(路徑)
  • stroke() 繪制已定義的路徑
  • moveTo() 把路徑移動到畫布中的指定點,不創建線條
  • lineTo() 添加一個新點,然后在畫布中創建從該點到最后指定點的線條
  • 開啟和關閉路徑
  • beginPath() 起始一條路徑,或重置當前路徑
  • closePath() 創建從當前點回到起始點的路徑

繪制圓弧

  • arc() 創建弧/曲線(用于創建圓形或部分圓)

  • arcTo(x1,y1,x2,y2,r) 創建兩切線之間的弧/曲線,點1坐標,點2坐標,半徑

    ctx.beginPath();
    ctx.moveTo(200,300);
    ctx.arcTo(200,100,400,100,100)
    ctx.lineTo(400,100);
    ctx.stroke();
    
    //封裝繪制圓角矩形的函數
        function roundRect(x,y,w,h,r){
            ctx.beginPath()
            ctx.moveTo(x,y+r)
            ctx.arcTo(x,y,x+w,y,r)
            ctx.arcTo(x+w,y,x+w,y+h,r)
            ctx.arcTo(x+w,y+h,x,y+h,r)
            ctx.arcTo(x,y+h,x,y,r)
            ctx.closePath()
            ctx.stroke()
        }
    
  • quadraticCurveTo(cx,cy,x,y) 創建二次貝塞爾曲線
    二次貝塞爾曲線需要兩個點。第一個點是用于二次貝塞爾計算中的控制點,第二個點是曲線的結束點。曲線的開始點是當前路徑中最后一個點。如果路徑不存在,那么請使用 beginPath() 和 moveTo() 方法來定義開始點。

  • bezierCurveTo(c1x,c1y,c2x,c2y,x,y) 創建三次方貝塞爾曲線
    提示:三次貝塞爾曲線需要三個點。前兩個點是用于三次貝塞爾計算中的控制點,第三個點是曲線的結束點。曲線的開始點是當前路徑中最后一個點。如果路徑不存在,那么請使用 beginPath() 和 moveTo() 方法來定義開始點。

  • clip() 從原始畫布剪切任意形狀和尺寸的區域

  • isPointInPath() 如果指定的點位于當前路徑中,則返回 true,否則返回 false

// 二次方貝塞爾曲線
        ctx.beginPath()
        ctx.moveTo(50,50)
        ctx.quadraticCurveTo(150,200,300,50);
        ctx.stroke()

        //為了更好的理解繪制原理,這里我們將控制線也繪制出來
        ctx.beginPath()
        ctx.strokeStyle = "blue"
        ctx.lineWidth=1
        ctx.moveTo(50,50)
        ctx.lineTo(150,200)
        ctx.lineTo(300,50)
        ctx.stroke()

        //三次方貝塞爾曲線
        ctx.beginPath()
        ctx.lineWidth=3
        ctx.fillStyle = "orange"
        ctx.strokeStyle = "green"
        ctx.moveTo(350,50)
        ctx.bezierCurveTo(400,150,600,200,700,50);
        ctx.stroke()

        //為了更好的理解繪制原理,這里我們將控制線也繪制出來
        ctx.beginPath()
        ctx.strokeStyle = "blue"
        ctx.lineWidth=1
        ctx.moveTo(350,50)
        ctx.lineTo(400,150)
        ctx.moveTo(600,200)
        ctx.lineTo(700,50)
        ctx.stroke()

顏色、樣式和陰影

  • fillStyle 設置或返回用于填充繪畫的顏色、漸變或模式
  • strokeStyle 設置或返回用于筆觸的顏色、漸變或模式
  • 陰影
    • shadowColor 設置或返回用于陰影的顏色
    • shadowBlur 設置或返回用于陰影的模糊級別
    • shadowOffsetX 設置或返回陰影距形狀的水平距離
    • shadowOffsetY 設置或返回陰影距形狀的垂直距離
  • 漸變
    • createLinearGradient(x0,y0,x1,y1) 創建線性漸變(用在畫布內容上)
    • createRadialGradient(x0,y0,r0,x1,y1,r1) 創建放射狀/環形的漸變(用在畫布內容上)
    • addColorStop() 規定漸變對象中的顏色和停止位置
  • createPattern(image,"repeat|repeat-x|repeat-y|no-repeat")在指定的方向上重復指定的元素
    • createPattern() 方法在指定的方向內重復指定的元素。
    • 元素可以是圖片、視頻,或者其他 canvas 元素。
    • 被重復的元素可用于繪制/填充矩形、圓形或線條等等

CanvasPattern對象開始平鋪圖像的參考起點并不是我們當前繪制圖形的左上角,而是整個canvas畫布的左上角,確切地說,即canvas的起點坐標(0,0)。

注意:如果createPattern()方法的image參數值不是當前頁面一個已經存在的Image對象或Canvas對象,那么我們需要等待瀏覽器將圖片加載完畢后才能調用createPattern()方法及后續操作,否則將無法正確顯示對應的圖形。

// ctx.shadowColor = 'rgb(75, 71, 230)';
// ctx.shadowOffsetX = 5;
// ctx.shadowOffsetY = 5;
// ctx.shadowBlur = 10;
//
// ctx.fillRect(100,100,100,100);
//
// // var gradient = ctx.createLinearGradient(300,100,400,100);
// var gradient = ctx.createRadialGradient(350,150,10,350,150,100);
// gradient.addColorStop(0,'rgb(52, 213, 55)');
// gradient.addColorStop(0.25,'rgb(213, 96, 52)');
// gradient.addColorStop(0.5,'rgb(52, 203, 213)');
// gradient.addColorStop(0.75,'rgb(104, 52, 213)');
// gradient.addColorStop(1,'rgb(210, 213, 52)');
// ctx.fillStyle = gradient;
// ctx.fillRect(300,100,100,100);

var img = new Image();
img.src = './xj2.png';
img.onload = function () {
    // 創建CanvasPattern對象,指定上述圖片進行水平的重復平鋪
    var pattern = ctx.createPattern(img,"repeat");
    ctx.fillStyle= pattern;
    ctx.fillRect(0,0,500,800);
}

文本

  1. 屬性
    • font 設置或返回文本內容的當前字體屬性
    • textAlign 設置或返回文本內容的當前對齊方式
      • start 默認。文本在指定的位置開始。
      • end 文本在指定的位置結束。
      • center 文本的中心被放置在指定的位置。
      • left 文本左對齊。
      • right 文本右對齊。
    • textBaseline 設置或返回在繪制文本時使用的當前文本基線
      • top 文本基線是 em 方框的頂端。
      • bottom 文本基線是 em 方框的底端。
      • middle 文本基線是 em 方框的正中。
      • alphabetic 默認。文本基線是普通的字母基線。
      • ideographic 文本基線是表意基線。一般用于繪制中文或日文字符串。
      • hanging 文本基線是懸掛基線。一般用于繪制印度語字符串
    ```
    ctx.beginPath();
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';
    ctx.font = '50px 宋體';
    ctx.fillText('我',100,100);
    ctx.strokeText('我',200,200);
    document.write(ctx.measureText(ctx).width);
    ```
  • 方法
    • fillText() 在畫布上繪制“被填充的”文本
    • strokeText() 在畫布上繪制文本(無填充)
    • measureText() 返回包含指定文本寬度的對象 語法:context.measureText(text).width;

measureText的返回值是一個對象,但里面只有一個屬性:width,本來文字的尺寸應該有width也有height,但canvas中的文字連行高都沒有,所以measureText也沒法得出高度。

measureText只是單純的測量文字,與是否把文字寫到canvas上無關。

轉換

  • translate() 重新映射畫布上的 (0,0) 位置(即移動坐標原點)
  • scale() 縮放當前繪圖至更大或更小
    溫馨提示:如果對繪圖進行縮放,所有之后的繪圖也會被縮放。定位也會被縮放。如果您 scale(2,2),那么繪圖將定位于距離畫布左上角兩倍遠的位置。
  • rotate() 旋轉當前繪圖
    注意參數單位為弧度。如需將角度轉換為弧度,請使用 degrees*Math.PI/180 公式進行計算。
  • transform() 替換繪圖的當前轉換矩陣
  • setTransform() 將當前轉換重置為單位矩陣。然后運行 transform()
//縮放\平移\旋轉
ctx.translate(100,100);
ctx.scale(2,2);
ctx.rotate(15*Math.PI/180);

狀態的保存和恢復

  1. save() 保存當前環境的狀態
    ctx.save();// 保存當前繪圖狀態
  2. restore() 返回之前保存過的路徑狀態和屬性
    ctx.restore();
    注意:可以多次保存,逐級恢復;最后保存的最先還原!restore總是還原離他最近的save點(已經還原的不能第2次還原到他)。
<script type="text/javascript">
var c = document.getElementById('canvas');
var ctx = c.getContext('2d');
ctx.lineWidth = 5;
ctx.fillStyle = 'rgb(76, 207, 106)';
ctx.strokeStyle = 'rgb(23, 26, 139)';

var i = 0;
var j=100;
var step=-1;
function test() {
    i++;
    if(j==200){
        step=-1
    }else if(j==1){
        step=1
    }
    j+=step;
    ctx.save()
    ctx.clearRect(0,0,c.width,c.height);
    ctx.scale(j/100,j/100);
    ctx.translate(c.width/2,c.height/2);
    ctx.rotate(i*15*Math.PI/180);
    ctx.translate(-50,-50);
    ctx.strokeRect(0,0,100,100);
    ctx.fillRect(0,0,100,100);
    ctx.restore()
}
setInterval('test()',10);
</script>
rect.gif

合成

  1. globalAlpha 設置或返回繪圖的當前 alpha 或透明值
  • globalCompositeOperation 設置或返回新圖像如何繪制到已有的圖像上
    • source-over 默認。在目標圖像上顯示源圖像。
    • source-atop 在目標圖像頂部顯示源圖像。源圖像位于目標圖像之外的部分是不可見的。
    • source-in 在目標圖像中顯示源圖像。只有目標圖像內的源圖像部分會顯示,目標圖像是透明的。
    • source-out 在目標圖像之外顯示源圖像。只會顯示目標圖像之外源圖像部分,目標圖像是透明的。
    • destination-over 在源圖像上方顯示目標圖像。
    • destination-atop 在源圖像頂部顯示目標圖像。源圖像之外的目標圖像部分不會被顯示。
    • destination-in 在源圖像中顯示目標圖像。只有源圖像內的目標圖像部分會被顯示,源圖像是透明的。
    • destination-out 在源圖像外顯示目標圖像。只有源圖像外的目標圖像部分會被顯示,源圖像是透明的。
    • lighter 顯示源圖像 + 目標圖像。這個值與順序無關,如果源與目標重疊,就將兩者的顏色值想加。得到的顏色值的最大取值為 255,結果就為白色。
    • copy 顯示源圖像。忽略目標圖像。這個值與順序無關,只繪制源,覆蓋掉目標。
    • xor 使用異或操作對源圖像與目標圖像進行組合。這個值與順序無關,只繪制出不重疊的源與目標區域。所有重疊的部分都變成透明的
      ctx.globalCompositeOperation = 'xor';

圖像繪制

  1. drawImage(img,sx,sy,swidth,sheight,x,y,width,height) 向畫布上繪制圖像、畫布或視頻

        • img 規定要使用的圖像、畫布或視頻。
        • sx 可選。開始剪切的 x 坐標位置。
        • sy 可選。開始剪切的 y 坐標位置。
        • swidth 可選。被剪切圖像的寬度。
        • sheight 可選。被剪切圖像的高度。
        • x 在畫布上放置圖像的 x 坐標位置。
        • y 在畫布上放置圖像的 y 坐標位置。
        • width 可選。要使用的圖像的寬度。(伸展或縮小圖像)
        • height 可選。要使用的圖像的高度。(伸展或縮小圖像)
    • drawImage(image,x,y) : 在canvas中(x,y)處繪制圖片。
    • drawImage(image,x,y,width,height) : 在canvas中(x,y)處繪制圖片,并將其縮放到指定的寬度和高度。
    • drawImage(image,sourceX,sourceY,sourceWidth,sourceHeight,x,y,width,height) :
      從圖片中切割出一個矩形區域(sourceX,sourceY,sourceWidth,sourceHeight),縮放到指定的寬度和高度,并在canvas中(x,y)繪制出來。
    // 在圖片未被加載錢不能對其繪制
    // window.onload=function () {
    //  ctx.drawImage(img,0,0);
    // }
    img.onload = function () {
        ctx.drawImage(img,0,0,100,100,0,0,100,100);
    }
    

像素操作

  1. 屬性
    • width 返回 ImageData 對象的寬度(可以理解為一行像素的個數)
    • height 返回 ImageData 對象的高度(可以理解為一列像素的個數)
    • data 返回一個對象,其包含指定的 ImageData 對象的圖像數據
      • 該對象包含每一個像素的四個rgba值,注意每個值都在0-255之間
      • 這個四個參數和CSS中講的rgba顏色表示法原理相同,四個參數分別表示紅、綠、藍以及透明度。
      • 所不同的是這里的透明度取值也是0-255,255表示完全不透明,0表示完全透明
  • 方法
    • getImageData(x,y,w,h) 返回 ImageData 對象,該對象為畫布上指定的矩形復制像素數據

    • putImageData(imgData,dx,dy,dirtyX,dirtyY,w,h) 把圖像數據(從指定的 ImageData 對象)放回畫布上
      首先討論第一種最簡單的putImageData用法,即putImageData(imgData,dirtyX,dirtyY),在解釋其他參數

      • imgData 規定要放回畫布的 ImageData 對象。
      • dx/dy ImageData 對象左上角的 x/y坐標,以像素計。即準備繪制圖像的起點坐標.
      • [dirtyX,dirtyY,w,h]為一組可選參數,該參數確定了一個以dx和dy坐標原點的矩形,分別表示矩形的起點和寬高,該矩形把將要繪制的圖像限定在矩形區域內.
      • 溫馨提示:如果用繪入外部圖片的辦法測試該屬性,在本地測試會出錯,這是由于javaScript的同源策略對context.getImageDate的影響,該策略是基于瀏覽器的安全,禁用會造成安全隱患。可以通過搭建一個本地站點,將文檔放到站點的方法測試。對于這一點在本課程中不做過多講解。
    • createImageData() 創建新的、空白的 ImageData 對象

      • var imgData=context.createImageData(width,height);以指定的尺寸(以像素計)創建新的 ImageData 對象
      • var imgData=context.createImageData(imageData)創建與指定的另一個 ImageData 對象尺寸相同的新 ImageData 對象(不會復制圖像數據)
      <script type="text/javascript">
      var c = document.getElementById('canvas');
      var ctx = c.getContext('2d');
      var img= new Image();
      img.onload = function () {
          ctx.drawImage(img,0,0,300,200);
      }
      img.src = './tooopen_sy_172649745666.jpg'
      
      function putImg() {
          var imgData = ctx.getImageData(0,0,300,200);
          ctx.putImageData(imgData,310,0,50,0,100,100);
      }
      
      // 反色繪制
      function fs() {
          ctx.clearRect(300,0,300,200);
          var imgData = ctx.getImageData(0,0,300,200);
          for (var i = 0; i < imgData.data.length; i+=4) {
              imgData.data[i+0] = 255-imgData.data[i+0];
              imgData.data[i+1] = 255-imgData.data[i+1];
              imgData.data[i+2] = 255-imgData.data[i+2];
              // imgData.data[i+3] = 255 - imgData.data[i+3];
          }
          ctx.putImageData(imgData,310,0);
      }
      
      // 濾鏡
      function lj() {
          ctx.clearRect(300,0,300,200);
          var imgData = ctx.getImageData(0,0,300,200);
          for (var i = 0; i < imgData.data.length; i+=4) {
              imgData.data[i] = 0;
          }
          ctx.putImageData(imgData,310,0);
      }
      
    </script>
    ```
img.gif

canvas畫布內容導出為圖像

  1. toDataURL()這個方法能把畫布里的圖案轉變成base64編碼格式的png,然后返回 Data URL數據。
  • 溫馨提示:以前多數瀏覽器不支持canvas中的內容直接右鍵保存為圖片格式。但現在大多數瀏覽器都是支持的。

面向畫布(Canvas)的JavaScript庫

  1. EaselJS 是一個封裝了 HTML5 畫布(Canvas) 元素的 JavaScript 庫。
  • jCanvaScript面向HTML5畫布(canvas)的Javascript類庫,它提供了許多方法用于簡化處理HTML5畫布(canvas)元素的內容,只要支持canvas和javascript的瀏覽器都可以使用它,包括iPhone、iPad和android等平臺。
  • Processing.js是一個開放的編程語言,在不使用Flash或Java小程序的前提下,可以實現程序圖像、動畫和互動的應用。Processing.js是輕量,易于了解掌握的理想工具,可用于可視化的數據,創建用戶界面和開發基于Web的游戲。
  • FABRIC.JS是一款簡單而強大的JavaScript Canvas 庫,提供了互動的對象模型,同時還包含 Canvas-to-SVG 解析器。
  • oCanvas是一個JavaScript框架,用于簡化HTML5 Canvas標簽的使用,可以利用對象來代替像素。 oCanvas 可以幫助你很容易的在 HTML5 的 Canvas 標簽上創建對象,并且創建這些對象的動畫。
  • jCanvas 就是一個 jQuery 的繪圖插件,它封裝了一些繪制圖形的方法,只需編寫幾行代碼即可生成圖形。
  • RGraph是一個使用HTML5 Canvas標簽實現的圖表制作Library。利用該Library生成的Chart具有可交互性,當鼠標點擊或移過時會顯示相應的信息,可以動態加載Chart或對特殊點進行縮放。
  • Two.js 是面向現代 Web 瀏覽器的一個二維繪圖 API。Two.js 可以用于多個場合:SVG,Canvas 和 WebGL,旨在使平面形狀和動畫的創建更方便,更簡潔。
  • ......
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容

  • 一:canvas簡介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標簽 ②:HTML5 ...
    GreenHand1閱讀 4,702評論 2 32
  • 一、canvas簡介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標簽 Canvas是一個矩形區...
    Looog閱讀 3,945評論 3 40
  • 一、簡介 HTML5 中的定義:“它是依賴分辨率的位圖畫布,你可以在 canvas 上面繪制任何圖形,甚至加載照片...
    destiny0904閱讀 10,564評論 1 4
  • 一、canvas簡介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標簽 Canvas是一個矩形區...
    J_L_L閱讀 1,530評論 0 4
  • 信仰是開在墻角的一朵花,雖不顯眼,但彌漫的芳香卻能沁人心脾;信仰是行駛在海洋上的一掛帆,雖然渺小,卻能乘長風破萬里...
    夏染涼閱讀 162評論 0 1