[{"data":1,"prerenderedAt":765},["ShallowReactive",2],{"blog-canvas-transformations":3},{"id":4,"title":5,"body":6,"description":15,"extension":755,"meta":756,"navigation":83,"path":761,"seo":762,"stem":763,"__hash__":764},"blog\u002Fblog\u002Fcanvas-transformations.md","HTML5 Canvas Transformations: Translate, Rotate, and Scale",{"type":7,"value":8,"toc":753},"minimark",[9,749],[10,11,12,402],"i18n-text",{},[13,14,16,20,29,40,53,62,102,109,120,206,213,227,303,310,324,331],"template",{"v-slot:en":15},"",[17,18,5],"h1",{"id":19},"html5-canvas-transformations-translate-rotate-and-scale",[21,22,23,24,28],"p",{},"Once you have mastered drawing basic shapes, the next essential skill in canvas game development is understanding ",[25,26,27],"strong",{},"Transformations",". This includes moving, rotating, and scaling (or flipping) objects.",[21,30,31,32,35,36,39],{},"The most important concept in Canvas transformations is that you ",[25,33,34],{},"don't rotate or scale the shape itself",". Instead, you transform the ",[25,37,38],{},"entire canvas coordinate system"," before drawing the shape, and then you revert the coordinate system back. Let's see how!",[41,42,44,45,49,50],"h2",{"id":43},"_1-state-management-save-and-restore","1. State Management: ",[46,47,48],"code",{},"save()"," and ",[46,51,52],{},"restore()",[21,54,55,56,58,59,61],{},"Since transformations affect the entire canvas globally, you must use ",[46,57,48],{}," to store the current canvas state, apply your transformations, draw, and finally use ",[46,60,52],{}," to bring the canvas back to normal.",[63,64,68],"pre",{"className":65,"code":66,"language":67,"meta":15,"style":15},"language-javascript shiki shiki-themes github-light github-dark","ctx.save(); \u002F\u002F Save the default un-transformed state\n\n\u002F\u002F ... Apply transformations and draw here ...\n\nctx.restore(); \u002F\u002F Revert back to the un-transformed state\n","javascript",[46,69,70,78,85,91,96],{"__ignoreMap":15},[71,72,75],"span",{"class":73,"line":74},"line",1,[71,76,77],{},"ctx.save(); \u002F\u002F Save the default un-transformed state\n",[71,79,81],{"class":73,"line":80},2,[71,82,84],{"emptyLinePlaceholder":83},true,"\n",[71,86,88],{"class":73,"line":87},3,[71,89,90],{},"\u002F\u002F ... Apply transformations and draw here ...\n",[71,92,94],{"class":73,"line":93},4,[71,95,84],{"emptyLinePlaceholder":83},[71,97,99],{"class":73,"line":98},5,[71,100,101],{},"ctx.restore(); \u002F\u002F Revert back to the un-transformed state\n",[41,103,105,106],{"id":104},"_2-moving-the-origin-translatex-y","2. Moving the Origin: ",[46,107,108],{},"translate(x, y)",[21,110,111,112,115,116,119],{},"By default, the origin ",[46,113,114],{},"(0, 0)"," is at the top-left corner of the canvas. ",[46,117,118],{},"translate"," moves this origin point. If you want to rotate an object around its center, you must first move the coordinate system's origin to the exact center of where you want to draw the object.",[63,121,123],{"className":65,"code":122,"language":67,"meta":15,"style":15},"const x = 100; \u002F\u002F Position X\nconst y = 100; \u002F\u002F Position Y\nconst width = 50;\nconst height = 50;\n\nctx.save();\nctx.translate(x + width \u002F 2, y + height \u002F 2); \u002F\u002F Move origin to object's center\n\n\u002F\u002F Now, drawing at (0, 0) is actually drawing exactly at our translated center\nctx.fillStyle = 'blue';\n\n\u002F\u002F We must draw from -width\u002F2, -height\u002F2 because the origin is exactly in the middle!\nctx.fillRect(-width \u002F 2, -height \u002F 2, width, height); \n\nctx.restore(); \u002F\u002F Return origin to top-left (0, 0)\n",[46,124,125,130,135,140,145,149,155,161,166,172,178,183,189,195,200],{"__ignoreMap":15},[71,126,127],{"class":73,"line":74},[71,128,129],{},"const x = 100; \u002F\u002F Position X\n",[71,131,132],{"class":73,"line":80},[71,133,134],{},"const y = 100; \u002F\u002F Position Y\n",[71,136,137],{"class":73,"line":87},[71,138,139],{},"const width = 50;\n",[71,141,142],{"class":73,"line":93},[71,143,144],{},"const height = 50;\n",[71,146,147],{"class":73,"line":98},[71,148,84],{"emptyLinePlaceholder":83},[71,150,152],{"class":73,"line":151},6,[71,153,154],{},"ctx.save();\n",[71,156,158],{"class":73,"line":157},7,[71,159,160],{},"ctx.translate(x + width \u002F 2, y + height \u002F 2); \u002F\u002F Move origin to object's center\n",[71,162,164],{"class":73,"line":163},8,[71,165,84],{"emptyLinePlaceholder":83},[71,167,169],{"class":73,"line":168},9,[71,170,171],{},"\u002F\u002F Now, drawing at (0, 0) is actually drawing exactly at our translated center\n",[71,173,175],{"class":73,"line":174},10,[71,176,177],{},"ctx.fillStyle = 'blue';\n",[71,179,181],{"class":73,"line":180},11,[71,182,84],{"emptyLinePlaceholder":83},[71,184,186],{"class":73,"line":185},12,[71,187,188],{},"\u002F\u002F We must draw from -width\u002F2, -height\u002F2 because the origin is exactly in the middle!\n",[71,190,192],{"class":73,"line":191},13,[71,193,194],{},"ctx.fillRect(-width \u002F 2, -height \u002F 2, width, height); \n",[71,196,198],{"class":73,"line":197},14,[71,199,84],{"emptyLinePlaceholder":83},[71,201,203],{"class":73,"line":202},15,[71,204,205],{},"ctx.restore(); \u002F\u002F Return origin to top-left (0, 0)\n",[41,207,209,210],{"id":208},"_3-rotating-shapes-rotateangle","3. Rotating Shapes: ",[46,211,212],{},"rotate(angle)",[21,214,215,218,219,221,222,226],{},[46,216,217],{},"ctx.rotate()"," rotates the grid around the current ",[46,220,114],{}," origin point. This is why we almost always translate the origin to the center of the shape ",[223,224,225],"em",{},"first",". Angles must be in radians, not degrees.",[63,228,230],{"className":65,"code":229,"language":67,"meta":15,"style":15},"const angleInDegrees = 45;\nconst angleInRadians = angleInDegrees * Math.PI \u002F 180;\n\nctx.save();\n\u002F\u002F 1. Move origin to center point\nctx.translate(150, 150);\n\n\u002F\u002F 2. Rotate the grid\nctx.rotate(angleInRadians);\n\n\u002F\u002F 3. Draw shape centered at the new origin (0, 0)\nctx.fillStyle = 'red';\n\u002F\u002F Draws a 50x50 rotated square\nctx.fillRect(-25, -25, 50, 50); \nctx.restore();\n",[46,231,232,237,242,246,250,255,260,264,269,274,278,283,288,293,298],{"__ignoreMap":15},[71,233,234],{"class":73,"line":74},[71,235,236],{},"const angleInDegrees = 45;\n",[71,238,239],{"class":73,"line":80},[71,240,241],{},"const angleInRadians = angleInDegrees * Math.PI \u002F 180;\n",[71,243,244],{"class":73,"line":87},[71,245,84],{"emptyLinePlaceholder":83},[71,247,248],{"class":73,"line":93},[71,249,154],{},[71,251,252],{"class":73,"line":98},[71,253,254],{},"\u002F\u002F 1. Move origin to center point\n",[71,256,257],{"class":73,"line":151},[71,258,259],{},"ctx.translate(150, 150);\n",[71,261,262],{"class":73,"line":157},[71,263,84],{"emptyLinePlaceholder":83},[71,265,266],{"class":73,"line":163},[71,267,268],{},"\u002F\u002F 2. Rotate the grid\n",[71,270,271],{"class":73,"line":168},[71,272,273],{},"ctx.rotate(angleInRadians);\n",[71,275,276],{"class":73,"line":174},[71,277,84],{"emptyLinePlaceholder":83},[71,279,280],{"class":73,"line":180},[71,281,282],{},"\u002F\u002F 3. Draw shape centered at the new origin (0, 0)\n",[71,284,285],{"class":73,"line":185},[71,286,287],{},"ctx.fillStyle = 'red';\n",[71,289,290],{"class":73,"line":191},[71,291,292],{},"\u002F\u002F Draws a 50x50 rotated square\n",[71,294,295],{"class":73,"line":197},[71,296,297],{},"ctx.fillRect(-25, -25, 50, 50); \n",[71,299,300],{"class":73,"line":202},[71,301,302],{},"ctx.restore();\n",[41,304,306,307],{"id":305},"_4-scaling-and-flipping-scalex-y","4. Scaling and Flipping: ",[46,308,309],{},"scale(x, y)",[21,311,312,315,316,319,320,323],{},[46,313,314],{},"ctx.scale(x, y)"," scales the current grid. ",[46,317,318],{},"x: 2"," makes things twice as wide. ",[46,321,322],{},"x: 0.5"," makes them half size.",[21,325,326,327,330],{},"A very common trick in game development is to flip an image or shape horizontally (like a character turning left or right). You can do this by using a ",[25,328,329],{},"negative scale","!",[63,332,334],{"className":65,"code":333,"language":67,"meta":15,"style":15},"ctx.save();\n\u002F\u002F 1. Move origin to the object's center first\nctx.translate(250, 200);\n\n\u002F\u002F 2. Flip horizontally (x = -1) and keep vertical scale normal (y = 1)\nctx.scale(-1, 1);\n\n\u002F\u002F 3. Draw element\nctx.font = '30px Arial';\nctx.textAlign = 'center';\nctx.textBaseline = 'middle';\n\u002F\u002F The text will be drawn backwards (flipped) like a mirror\nctx.fillText('FLIPPED!', 0, 0); \nctx.restore();\n",[46,335,336,340,345,350,354,359,364,368,373,378,383,388,393,398],{"__ignoreMap":15},[71,337,338],{"class":73,"line":74},[71,339,154],{},[71,341,342],{"class":73,"line":80},[71,343,344],{},"\u002F\u002F 1. Move origin to the object's center first\n",[71,346,347],{"class":73,"line":87},[71,348,349],{},"ctx.translate(250, 200);\n",[71,351,352],{"class":73,"line":93},[71,353,84],{"emptyLinePlaceholder":83},[71,355,356],{"class":73,"line":98},[71,357,358],{},"\u002F\u002F 2. Flip horizontally (x = -1) and keep vertical scale normal (y = 1)\n",[71,360,361],{"class":73,"line":151},[71,362,363],{},"ctx.scale(-1, 1);\n",[71,365,366],{"class":73,"line":157},[71,367,84],{"emptyLinePlaceholder":83},[71,369,370],{"class":73,"line":163},[71,371,372],{},"\u002F\u002F 3. Draw element\n",[71,374,375],{"class":73,"line":168},[71,376,377],{},"ctx.font = '30px Arial';\n",[71,379,380],{"class":73,"line":174},[71,381,382],{},"ctx.textAlign = 'center';\n",[71,384,385],{"class":73,"line":180},[71,386,387],{},"ctx.textBaseline = 'middle';\n",[71,389,390],{"class":73,"line":185},[71,391,392],{},"\u002F\u002F The text will be drawn backwards (flipped) like a mirror\n",[71,394,395],{"class":73,"line":191},[71,396,397],{},"ctx.fillText('FLIPPED!', 0, 0); \n",[71,399,400],{"class":73,"line":197},[71,401,302],{},[13,403,404,408,415,430,439,448,476,482,491,571,577,591,663,669,675,678],{"v-slot:id":15},[17,405,407],{"id":406},"transformasi-html5-canvas-translate-rotate-dan-scale","Transformasi HTML5 Canvas: Translate, Rotate, dan Scale",[21,409,410,411,414],{},"Setelah menguasai cara menggambar bentuk dasar, kemampuan penting berikutnya dalam pembuatan game canvas adalah memahami ",[25,412,413],{},"Transformasi",". Ini termasuk memindahkan orientasi titik posisi (Translate), memutar arah kemiringan (Rotate), serta mengubah ukuran atau membalikkan arah sumbu (Scale \u002F Flip) bagi object apapun yang digambar selanjutnya.",[21,416,417,418,421,422,425,426,429],{},"Konsep yang paling mendasar di Canvas Game Engine adalah ",[25,419,420],{},"Anda tidak memutar atau mengubah orientasi objek yang digambar tersebut",". Yang dilakukan sebenarnya ialah ",[25,423,424],{},"memutar orientasi seluruh koordinat sumbu canvas (ruang kerjanya)"," ",[223,427,428],{},"sebelum"," merender memoles gambar yang diiginkan, dan barulah seluruh setingan sumbu dipulihkan kembali ke semula posisinya.",[41,431,433,434,436,437],{"id":432},"_1-mengelola-state-ruang-kerja-save-dan-restore","1. Mengelola State Ruang Kerja: ",[46,435,48],{}," dan ",[46,438,52],{},[21,440,441,442,444,445,447],{},"Oleh karena orientasi transformasi selalu menimpa ke keseluruhan grid Canvas secara global (merubah dunia), Anda diwajibkan untuk biasa menggunakan metode ",[46,443,48],{}," yang berguna merekam rekam jejak status aslinya (normal dunia sebelum digeser\u002Fdiputar). Setelah menerapkan pergerakan, Anda tinggal memanggil fungsi pendamping pasangannya yaitu ",[46,446,52],{}," agar seluruh orientasi titik Canvas berbalik pemulihannya ke kondisi normalnya tadi.",[63,449,451],{"className":65,"code":450,"language":67,"meta":15,"style":15},"ctx.save(); \u002F\u002F Simpan koordinat dan orientasi normal-nya saat ini\n\n\u002F\u002F ... Terapkan modifikasi sumbu XY dengan Translate\u002FRotate, dilanjut Menggambar suatu wujud di dunia\u002Fgrid mutasi ini ...\n\nctx.restore(); \u002F\u002F Pemulihan paksa kembali titik orientasi canvas dari track record 'save' sebelumnya.\n",[46,452,453,458,462,467,471],{"__ignoreMap":15},[71,454,455],{"class":73,"line":74},[71,456,457],{},"ctx.save(); \u002F\u002F Simpan koordinat dan orientasi normal-nya saat ini\n",[71,459,460],{"class":73,"line":80},[71,461,84],{"emptyLinePlaceholder":83},[71,463,464],{"class":73,"line":87},[71,465,466],{},"\u002F\u002F ... Terapkan modifikasi sumbu XY dengan Translate\u002FRotate, dilanjut Menggambar suatu wujud di dunia\u002Fgrid mutasi ini ...\n",[71,468,469],{"class":73,"line":93},[71,470,84],{"emptyLinePlaceholder":83},[71,472,473],{"class":73,"line":98},[71,474,475],{},"ctx.restore(); \u002F\u002F Pemulihan paksa kembali titik orientasi canvas dari track record 'save' sebelumnya.\n",[41,477,479,480],{"id":478},"_2-memindahkan-titik-origin-orientasi-poros-translatex-y","2. Memindahkan Titik Origin Orientasi Poros: ",[46,481,108],{},[21,483,484,485,487,488,490],{},"Setelan bawaannya, titik asal origin Canvas Canvas ",[46,486,114],{}," selalu berada mati di sudut paling kiri-atas. Kode ",[46,489,118],{}," sengaja difungsikan mentransportasikan pemindahan titik poros origin tersebut kemanapun area layar yang kita rencanakan orientasikan pergerakannya. Saat Anda berniat memutar sebuah objek berporos di tengah (berbasis center point objek-nya layaknya kincir\u002Fjarum jam), maka syarat pertama absolut adalah Anda WAJIB memindahkan sumbu (0,0) persis masuk menembus ditengah wujud objek target perputaran.",[63,492,494],{"className":65,"code":493,"language":67,"meta":15,"style":15},"const x = 100; \u002F\u002F Target Posisi X Asli\nconst y = 100; \u002F\u002F Target Posisi Y Asli\nconst lebar = 50;\nconst tinggi = 50;\n\nctx.save();\n\u002F\u002F Berlabuh memindahkan titik pusat 0,0 kanvas, tepat membelah pertengahan sumbu target Object\nctx.translate(x + lebar \u002F 2, y + tinggi \u002F 2); \n\n\u002F\u002F Karena target (0,0) kita kini bukan lagi dari ujung layar pojok kiri atas, melainkan sudah di per-tengahan objek yang ditarget ini\nctx.fillStyle = 'blue';\n\n\u002F\u002F Agar menggambarnya persis presisi di center, proses gambar persegi panjang wajib dimundurkan (- minus) dengan porsi dari setengah(2) ukurannya\nctx.fillRect(-lebar \u002F 2, -tinggi \u002F 2, lebar, tinggi); \n\nctx.restore(); \u002F\u002F Tarik pulang ruang kerja dunia kanvas ke pemusatan ujung 0,0 sudut kiri atas kembali.\n",[46,495,496,501,506,511,516,520,524,529,534,538,543,547,551,556,561,565],{"__ignoreMap":15},[71,497,498],{"class":73,"line":74},[71,499,500],{},"const x = 100; \u002F\u002F Target Posisi X Asli\n",[71,502,503],{"class":73,"line":80},[71,504,505],{},"const y = 100; \u002F\u002F Target Posisi Y Asli\n",[71,507,508],{"class":73,"line":87},[71,509,510],{},"const lebar = 50;\n",[71,512,513],{"class":73,"line":93},[71,514,515],{},"const tinggi = 50;\n",[71,517,518],{"class":73,"line":98},[71,519,84],{"emptyLinePlaceholder":83},[71,521,522],{"class":73,"line":151},[71,523,154],{},[71,525,526],{"class":73,"line":157},[71,527,528],{},"\u002F\u002F Berlabuh memindahkan titik pusat 0,0 kanvas, tepat membelah pertengahan sumbu target Object\n",[71,530,531],{"class":73,"line":163},[71,532,533],{},"ctx.translate(x + lebar \u002F 2, y + tinggi \u002F 2); \n",[71,535,536],{"class":73,"line":168},[71,537,84],{"emptyLinePlaceholder":83},[71,539,540],{"class":73,"line":174},[71,541,542],{},"\u002F\u002F Karena target (0,0) kita kini bukan lagi dari ujung layar pojok kiri atas, melainkan sudah di per-tengahan objek yang ditarget ini\n",[71,544,545],{"class":73,"line":180},[71,546,177],{},[71,548,549],{"class":73,"line":185},[71,550,84],{"emptyLinePlaceholder":83},[71,552,553],{"class":73,"line":191},[71,554,555],{},"\u002F\u002F Agar menggambarnya persis presisi di center, proses gambar persegi panjang wajib dimundurkan (- minus) dengan porsi dari setengah(2) ukurannya\n",[71,557,558],{"class":73,"line":197},[71,559,560],{},"ctx.fillRect(-lebar \u002F 2, -tinggi \u002F 2, lebar, tinggi); \n",[71,562,563],{"class":73,"line":202},[71,564,84],{"emptyLinePlaceholder":83},[71,566,568],{"class":73,"line":567},16,[71,569,570],{},"ctx.restore(); \u002F\u002F Tarik pulang ruang kerja dunia kanvas ke pemusatan ujung 0,0 sudut kiri atas kembali.\n",[41,572,574,575],{"id":573},"_3-merotasi-kemiringan-derajat-bentuk-rotateangle","3. Merotasi Kemiringan Derajat Bentuk: ",[46,576,212],{},[21,578,579,580,583,584,587,588,590],{},"Metode ",[46,581,582],{},"ctx.rotate(radiant)"," mencondongkan putaran satu ruang dimensi di koordinat rotasi pangkal origin titik ",[46,585,586],{},"(0,0)"," terkini. Inilah akar penyebab utama kenapa kita memprioritaskan proses geser poros (",[46,589,118],{},") pusat orientasi ketengah persis bentuk objek! (Kalau (0,0) nya tidak dipindahkan dari ujung kiri atas, maka objek Anda bukannya akan berputar melintir di tempat, melainkan sebaliknya berputar nyasar layaknya gerakan planet berevolusi memutari bingkai ujung ujung seluruh web Canvas screen!)",[63,592,594],{"className":65,"code":593,"language":67,"meta":15,"style":15},"const sudutDegree = 45; \u002F\u002F Angka derajat rotasi sudut\nconst hitunganRadian = sudutDegree * Math.PI \u002F 180; \u002F\u002F konversi ke hitungan Radian yang dipahami canvas\n\nctx.save();\n\u002F\u002F 1. Transplantasi\u002FGeser pemutar canvas poros ketengah sumbu object\nctx.translate(150, 150);\n\n\u002F\u002F 2. Putar kemiringan putaran seluruh medan orientasi (harus wajib dihitung kedalam Radian)\nctx.rotate(hitunganRadian);\n\n\u002F\u002F 3. Menggambar wujud ke poros koordinat (0,0) baru yg telah termiringkan tersebut\nctx.fillStyle = 'red';\n\u002F\u002F Berukuran lebar & tinggi (50x50), nilai posisi digeser x minus setengah dan y minus setengah (-25) kebalikannya \nctx.fillRect(-25, -25, 50, 50); \nctx.restore();\n",[46,595,596,601,606,610,614,619,623,627,632,637,641,646,650,655,659],{"__ignoreMap":15},[71,597,598],{"class":73,"line":74},[71,599,600],{},"const sudutDegree = 45; \u002F\u002F Angka derajat rotasi sudut\n",[71,602,603],{"class":73,"line":80},[71,604,605],{},"const hitunganRadian = sudutDegree * Math.PI \u002F 180; \u002F\u002F konversi ke hitungan Radian yang dipahami canvas\n",[71,607,608],{"class":73,"line":87},[71,609,84],{"emptyLinePlaceholder":83},[71,611,612],{"class":73,"line":93},[71,613,154],{},[71,615,616],{"class":73,"line":98},[71,617,618],{},"\u002F\u002F 1. Transplantasi\u002FGeser pemutar canvas poros ketengah sumbu object\n",[71,620,621],{"class":73,"line":151},[71,622,259],{},[71,624,625],{"class":73,"line":157},[71,626,84],{"emptyLinePlaceholder":83},[71,628,629],{"class":73,"line":163},[71,630,631],{},"\u002F\u002F 2. Putar kemiringan putaran seluruh medan orientasi (harus wajib dihitung kedalam Radian)\n",[71,633,634],{"class":73,"line":168},[71,635,636],{},"ctx.rotate(hitunganRadian);\n",[71,638,639],{"class":73,"line":174},[71,640,84],{"emptyLinePlaceholder":83},[71,642,643],{"class":73,"line":180},[71,644,645],{},"\u002F\u002F 3. Menggambar wujud ke poros koordinat (0,0) baru yg telah termiringkan tersebut\n",[71,647,648],{"class":73,"line":185},[71,649,287],{},[71,651,652],{"class":73,"line":191},[71,653,654],{},"\u002F\u002F Berukuran lebar & tinggi (50x50), nilai posisi digeser x minus setengah dan y minus setengah (-25) kebalikannya \n",[71,656,657],{"class":73,"line":197},[71,658,297],{},[71,660,661],{"class":73,"line":202},[71,662,302],{},[41,664,666,667],{"id":665},"_4-efek-balikcermin-flip-gambar-serta-membesarkan-resolusi-rasio-scaleflip-scalex-y","4. Efek Balik\u002FCermin Flip Gambar serta Membesarkan Resolusi Rasio (Scale\u002FFlip): ",[46,668,309],{},[21,670,671,672,674],{},"Metode pembesaran dimensi ini merombak pelebaran panjang dan lebar pembesaran seluruh grid sumbu dari pergesaran skala ukur (Angka defaultnya adalah 1.0). Kalau Anda mengetik code ",[46,673,318],{},", bentuk otomatis merentang ter-zoom pelebarannya serentak selebar dua(2) kali rentang panjang lipat.",[21,676,677],{},"Salah satu rahasia paling fundamental pada manipulasi grafis trik mem-balik (Flipping) Sprites karakter pemain\u002Fmusuh dalam sebuah Game Platformer maupun Sidescroll yang bergerak di Game Development (Berbalik hadap kiri\u002Fberubah posisi ke kanan belakang). Ternyata ini memakai kelemahan skala Minus (- 1)",[63,679,681],{"className":65,"code":680,"language":67,"meta":15,"style":15},"ctx.save();\n\u002F\u002F 1. Ubah poros point 0,0 ke badan pusat rotasinya\nctx.translate(250, 200);\n\n\u002F\u002F 2. Trik Memutarlompati Sumbu Orientasi Pembalik arah Gambar dengan ratio cerminan horizontal menggunakan penolakan minus (x = -1). Dimensi Vertical sengaja kita blok ditahan konstan (y = 1)\nctx.scale(-1, 1);\n\n\u002F\u002F 3. Gambaran Objek baru  di terjemahan efek Flip tersebut\nctx.font = '30px Arial';\nctx.textAlign = 'center';\nctx.textBaseline = 'middle';\n\n\u002F\u002F Karena orientasi dunianya terbalik(dari titik pusat yg kita atur tadi) - Text Yang Dituliskanpun Akan Jadi Terbaca seperti Tulisan Kaca Terbalik!\nctx.fillText('TEKS TERBALIK MENGHADAP KE KIRI!', 0, 0); \nctx.restore(); \u002F\u002F Pemulihan sumbu dimensi kembali normal\n",[46,682,683,687,692,696,700,705,709,713,718,722,726,730,734,739,744],{"__ignoreMap":15},[71,684,685],{"class":73,"line":74},[71,686,154],{},[71,688,689],{"class":73,"line":80},[71,690,691],{},"\u002F\u002F 1. Ubah poros point 0,0 ke badan pusat rotasinya\n",[71,693,694],{"class":73,"line":87},[71,695,349],{},[71,697,698],{"class":73,"line":93},[71,699,84],{"emptyLinePlaceholder":83},[71,701,702],{"class":73,"line":98},[71,703,704],{},"\u002F\u002F 2. Trik Memutarlompati Sumbu Orientasi Pembalik arah Gambar dengan ratio cerminan horizontal menggunakan penolakan minus (x = -1). Dimensi Vertical sengaja kita blok ditahan konstan (y = 1)\n",[71,706,707],{"class":73,"line":151},[71,708,363],{},[71,710,711],{"class":73,"line":157},[71,712,84],{"emptyLinePlaceholder":83},[71,714,715],{"class":73,"line":163},[71,716,717],{},"\u002F\u002F 3. Gambaran Objek baru  di terjemahan efek Flip tersebut\n",[71,719,720],{"class":73,"line":168},[71,721,377],{},[71,723,724],{"class":73,"line":174},[71,725,382],{},[71,727,728],{"class":73,"line":180},[71,729,387],{},[71,731,732],{"class":73,"line":185},[71,733,84],{"emptyLinePlaceholder":83},[71,735,736],{"class":73,"line":191},[71,737,738],{},"\u002F\u002F Karena orientasi dunianya terbalik(dari titik pusat yg kita atur tadi) - Text Yang Dituliskanpun Akan Jadi Terbaca seperti Tulisan Kaca Terbalik!\n",[71,740,741],{"class":73,"line":197},[71,742,743],{},"ctx.fillText('TEKS TERBALIK MENGHADAP KE KIRI!', 0, 0); \n",[71,745,746],{"class":73,"line":202},[71,747,748],{},"ctx.restore(); \u002F\u002F Pemulihan sumbu dimensi kembali normal\n",[750,751,752],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":15,"searchDepth":80,"depth":80,"links":754},[],"md",{"title_en":5,"title_id":407,"description_en":757,"description_id":758,"date":759,"readingTime":760},"Learn how to transform Canvas elements by changing the origin point using translate, rotating shapes, and flipping or scaling them.","Pelajari cara mengubah bentuk Canvas dengan memindahkan titik origin lewat translate, melakukan rotasi, sampai membalik\u002Fflip gambar.","2026-03-25","7 min read","\u002Fblog\u002Fcanvas-transformations",{"title":5,"description":15},"blog\u002Fcanvas-transformations","U2PaHHe_C5_3R3IFmkH3bS4XZugeXeyBg-rDdRMd8F8",1783751391741]