[{"data":1,"prerenderedAt":8531},["ShallowReactive",2],{"home-recent":3},[4,834,2198,2784,6868],{"id":5,"title":6,"body":7,"category":818,"createdAt":820,"description":821,"extension":822,"index":823,"meta":824,"navigation":92,"path":825,"publish":92,"seo":826,"series":823,"seriesTitle":823,"stem":827,"tag":828,"thumbnail":832,"updatedAt":820,"__hash__":833},"articles\u002Farticles\u002Faws-sam-disconnect-dymamodb-local.md","AWS SAMで作ったLamdaコードがローカルのDynamoDBに接続できないときの対処",{"type":8,"value":9,"toc":811},"minimark",[10,14,17,28,31,42,45,48,53,56,221,232,571,574,580,583,590,593,596,601,609,624,627,631,634,752,755,761,767,801,804,807],[11,12,13],"p",{},"こんにちはjunです。最近はこの静的ブログに動的な機能を追加するために、サーバーレス環境でのサービス開発を行っています。API gateway をトリガーとしてAWS Lambdaでコードを実行してDynamoDBで内容を保存するといったよくある構成で開発をしていました。",[11,15,16],{},"AWS Lambdaはweb上でもコードを書いて実行できますが、できたらローカル上でコードを書いてテストしてからデプロイしたいです。特に更新や改修の時はローカルで検証できることが好ましいです。",[11,18,19,20,27],{},"AWSはその辺も考えており、",[21,22,26],"a",{"href":23,"rel":24},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fja_jp\u002Fserverless-application-model\u002Flatest\u002Fdeveloperguide\u002Fwhat-is-sam.html",[25],"nofollow","AWS SAM(serverless application model)"," を用意してくれています。私も開発ではこのSAMを使用してローカルで構築後、テストして本番に適用しています。",[11,29,30],{},"ひとまずチュートリアルのデプロイができたので、DynamoDBを用いた環境をローカルに作ってコードをテストすることにしました。しかし、DynamoDBをscanする処理でいつもストップし、",[32,33,38],"pre",{"className":34,"code":36,"language":37},[35],"language-text","Inaccessible host: `127.0.0.1' at port `8000'. This service may not be available in the `ap-north-east1' region.\n","text",[39,40,36],"code",{"__ignoreMap":41},"",[11,43,44],{},"というメッセージでDynamoDBに接続できませんでした。ちなみにDynamoDBの環境はDockerを用いてローカルで構築しており、localost:8000に待機していました。DynamoDBのコンテナは起動しているのに、どうして接続できないのか悩んでいました。",[11,46,47],{},"結論を言うとDockerのネットワークの設定が間違っていたからです。詳細を解説します。",[49,50,52],"h2",{"id":51},"lambdaのコードとdynamodbのコンテナ設定","LambdaのコードとDynamoDBのコンテナ設定",[11,54,55],{},"DynamoDBはこちらのDocker imageを使用して、以下の設定を用いていました。（参考サイトからのコピペです...)",[32,57,62],{"className":58,"code":59,"filename":60,"language":61,"meta":41,"style":41},"language-yaml shiki shiki-themes material-theme-ocean","version: \"3\"\n\nservices:\n  dynamodb-local:\n    container_name: dynamodb-local\n    image: amazon\u002Fdynamodb-local\n    ports:\n      - 8000:8000\n    command: -jar DynamoDBLocal.jar -dbPath \u002Fdata -sharedDb\n    volumes:\n      - .\u002Fdata:\u002Fdata\n    networks:\n      - lambda-local\nnetworks:\n  lambda-local:\n    external: true\n","docker-compose.yml","yaml",[39,63,64,87,94,103,111,122,133,141,150,161,169,177,185,193,201,209],{"__ignoreMap":41},[65,66,69,73,77,80,84],"span",{"class":67,"line":68},"line",1,[65,70,72],{"class":71},"s-wAU","version",[65,74,76],{"class":75},"sAklC",":",[65,78,79],{"class":75}," \"",[65,81,83],{"class":82},"sfyAc","3",[65,85,86],{"class":75},"\"\n",[65,88,90],{"class":67,"line":89},2,[65,91,93],{"emptyLinePlaceholder":92},true,"\n",[65,95,97,100],{"class":67,"line":96},3,[65,98,99],{"class":71},"services",[65,101,102],{"class":75},":\n",[65,104,106,109],{"class":67,"line":105},4,[65,107,108],{"class":71},"  dynamodb-local",[65,110,102],{"class":75},[65,112,114,117,119],{"class":67,"line":113},5,[65,115,116],{"class":71},"    container_name",[65,118,76],{"class":75},[65,120,121],{"class":82}," dynamodb-local\n",[65,123,125,128,130],{"class":67,"line":124},6,[65,126,127],{"class":71},"    image",[65,129,76],{"class":75},[65,131,132],{"class":82}," amazon\u002Fdynamodb-local\n",[65,134,136,139],{"class":67,"line":135},7,[65,137,138],{"class":71},"    ports",[65,140,102],{"class":75},[65,142,144,147],{"class":67,"line":143},8,[65,145,146],{"class":75},"      -",[65,148,149],{"class":82}," 8000:8000\n",[65,151,153,156,158],{"class":67,"line":152},9,[65,154,155],{"class":71},"    command",[65,157,76],{"class":75},[65,159,160],{"class":82}," -jar DynamoDBLocal.jar -dbPath \u002Fdata -sharedDb\n",[65,162,164,167],{"class":67,"line":163},10,[65,165,166],{"class":71},"    volumes",[65,168,102],{"class":75},[65,170,172,174],{"class":67,"line":171},11,[65,173,146],{"class":75},[65,175,176],{"class":82}," .\u002Fdata:\u002Fdata\n",[65,178,180,183],{"class":67,"line":179},12,[65,181,182],{"class":71},"    networks",[65,184,102],{"class":75},[65,186,188,190],{"class":67,"line":187},13,[65,189,146],{"class":75},[65,191,192],{"class":82}," lambda-local\n",[65,194,196,199],{"class":67,"line":195},14,[65,197,198],{"class":71},"networks",[65,200,102],{"class":75},[65,202,204,207],{"class":67,"line":203},15,[65,205,206],{"class":71},"  lambda-local",[65,208,102],{"class":75},[65,210,212,215,217],{"class":67,"line":211},16,[65,213,214],{"class":71},"    external",[65,216,76],{"class":75},[65,218,220],{"class":219},"sbqyR"," true\n",[11,222,223,224,227,228,231],{},"上記の",[39,225,226],{},"- 8000:8000"," の通りlocalhostの8000にDynamoDBのエンドポイントが待機しています。\n",[39,229,230],{},"docker-compose up","してこの記述の通り、Lambdaのコードで以下のように記述しました。",[32,233,238],{"className":234,"code":235,"filename":236,"language":237,"meta":41,"style":41},"language-js shiki shiki-themes material-theme-ocean","const AWS = require('aws-sdk')\nlet response;\n\nvar dynamoOpt = {\n    endpoint: \"http:\u002F\u002Flocalhost:8000\",\n};\n\nexports.lambdaHandler = async (event, context) => {\n    let params = {\n            TableName:'table',\n        };\n\n        try{\n            const result = await dynamodb.scan(params).promise()\n            return {\n                statusCode: 200,\n                body: JSON.stringify(result.Items),\n            };\n        }catch (e){\n            return {\n                statusCode: 500,\n                body: e.message,\n            };\n        }\n}\n","app.js","js",[39,239,240,271,282,286,299,317,322,326,361,373,389,394,398,407,444,451,464,494,500,518,525,537,554,559,565],{"__ignoreMap":41},[65,241,242,246,250,253,257,260,263,266,268],{"class":67,"line":68},[65,243,245],{"class":244},"sJ14y","const",[65,247,249],{"class":248},"s0W1g"," AWS ",[65,251,252],{"class":75},"=",[65,254,256],{"class":255},"sdLwU"," require",[65,258,259],{"class":248},"(",[65,261,262],{"class":75},"'",[65,264,265],{"class":82},"aws-sdk",[65,267,262],{"class":75},[65,269,270],{"class":248},")\n",[65,272,273,276,279],{"class":67,"line":89},[65,274,275],{"class":244},"let",[65,277,278],{"class":248}," response",[65,280,281],{"class":75},";\n",[65,283,284],{"class":67,"line":96},[65,285,93],{"emptyLinePlaceholder":92},[65,287,288,291,294,296],{"class":67,"line":105},[65,289,290],{"class":244},"var",[65,292,293],{"class":248}," dynamoOpt ",[65,295,252],{"class":75},[65,297,298],{"class":75}," {\n",[65,300,301,304,306,308,311,314],{"class":67,"line":113},[65,302,303],{"class":71},"    endpoint",[65,305,76],{"class":75},[65,307,79],{"class":75},[65,309,310],{"class":82},"http:\u002F\u002Flocalhost:8000",[65,312,313],{"class":75},"\"",[65,315,316],{"class":75},",\n",[65,318,319],{"class":67,"line":124},[65,320,321],{"class":75},"};\n",[65,323,324],{"class":67,"line":135},[65,325,93],{"emptyLinePlaceholder":92},[65,327,328,331,334,337,340,343,347,350,353,356,359],{"class":67,"line":143},[65,329,330],{"class":75},"exports.",[65,332,333],{"class":255},"lambdaHandler",[65,335,336],{"class":75}," =",[65,338,339],{"class":244}," async",[65,341,342],{"class":75}," (",[65,344,346],{"class":345},"s7ZW3","event",[65,348,349],{"class":75},",",[65,351,352],{"class":345}," context",[65,354,355],{"class":75},")",[65,357,358],{"class":244}," =>",[65,360,298],{"class":75},[65,362,363,366,369,371],{"class":67,"line":152},[65,364,365],{"class":244},"    let",[65,367,368],{"class":248}," params",[65,370,336],{"class":75},[65,372,298],{"class":75},[65,374,375,378,380,382,385,387],{"class":67,"line":163},[65,376,377],{"class":71},"            TableName",[65,379,76],{"class":75},[65,381,262],{"class":75},[65,383,384],{"class":82},"table",[65,386,262],{"class":75},[65,388,316],{"class":75},[65,390,391],{"class":67,"line":171},[65,392,393],{"class":75},"        };\n",[65,395,396],{"class":67,"line":179},[65,397,93],{"emptyLinePlaceholder":92},[65,399,400,404],{"class":67,"line":187},[65,401,403],{"class":402},"s6cf3","        try",[65,405,406],{"class":75},"{\n",[65,408,409,412,415,417,420,423,426,429,431,434,436,438,441],{"class":67,"line":195},[65,410,411],{"class":244},"            const",[65,413,414],{"class":248}," result",[65,416,336],{"class":75},[65,418,419],{"class":402}," await",[65,421,422],{"class":248}," dynamodb",[65,424,425],{"class":75},".",[65,427,428],{"class":255},"scan",[65,430,259],{"class":71},[65,432,433],{"class":248},"params",[65,435,355],{"class":71},[65,437,425],{"class":75},[65,439,440],{"class":255},"promise",[65,442,443],{"class":71},"()\n",[65,445,446,449],{"class":67,"line":203},[65,447,448],{"class":402},"            return",[65,450,298],{"class":75},[65,452,453,456,458,462],{"class":67,"line":211},[65,454,455],{"class":71},"                statusCode",[65,457,76],{"class":75},[65,459,461],{"class":460},"sx098"," 200",[65,463,316],{"class":75},[65,465,467,470,472,475,477,480,482,485,487,490,492],{"class":67,"line":466},17,[65,468,469],{"class":71},"                body",[65,471,76],{"class":75},[65,473,474],{"class":248}," JSON",[65,476,425],{"class":75},[65,478,479],{"class":255},"stringify",[65,481,259],{"class":71},[65,483,484],{"class":248},"result",[65,486,425],{"class":75},[65,488,489],{"class":248},"Items",[65,491,355],{"class":71},[65,493,316],{"class":75},[65,495,497],{"class":67,"line":496},18,[65,498,499],{"class":75},"            };\n",[65,501,503,506,509,511,514,516],{"class":67,"line":502},19,[65,504,505],{"class":75},"        }",[65,507,508],{"class":402},"catch",[65,510,342],{"class":71},[65,512,513],{"class":248},"e",[65,515,355],{"class":71},[65,517,406],{"class":75},[65,519,521,523],{"class":67,"line":520},20,[65,522,448],{"class":402},[65,524,298],{"class":75},[65,526,528,530,532,535],{"class":67,"line":527},21,[65,529,455],{"class":71},[65,531,76],{"class":75},[65,533,534],{"class":460}," 500",[65,536,316],{"class":75},[65,538,540,542,544,547,549,552],{"class":67,"line":539},22,[65,541,469],{"class":71},[65,543,76],{"class":75},[65,545,546],{"class":248}," e",[65,548,425],{"class":75},[65,550,551],{"class":248},"message",[65,553,316],{"class":75},[65,555,557],{"class":67,"line":556},23,[65,558,499],{"class":75},[65,560,562],{"class":67,"line":561},24,[65,563,564],{"class":75},"        }\n",[65,566,568],{"class":67,"line":567},25,[65,569,570],{"class":75},"}\n",[11,572,573],{},"そしてビルドしてテストをしても",[32,575,578],{"className":576,"code":577,"language":37},[35],"sam build\nsam local invoke -e events\u002Fevent.json\n\nInaccessible host: `127.0.0.1' at port `8000'. This service may not be available in the `ap-north-east1' region.\n",[39,579,577],{"__ignoreMap":41},[11,581,582],{},"とDynamoDBのホストに接続できていないというエラーが発生しました。色々検索した結果、以下の記事がキーとなり解決しました。",[11,584,585],{},[21,586,589],{"href":587,"rel":588},"https:\u002F\u002Ffuture-architect.github.io\u002Farticles\u002F20200323\u002F",[25],"Serverless連載1: SAMを使ったローカルテスト（Go編）",[49,591,592],{"id":592},"解決法",[11,594,595],{},"上記記事の図をみて一気に理解できました。原因はSAMのコンテナがDynamoDBのコンテナに接続できず、またホスト（localhost)の指定が間違っていたからです。",[597,598,600],"h3",{"id":599},"samもdockerで実行されている","SAMもdockerで実行されている",[11,602,603,604],{},"SAMは自動デプロイだけでなく、ローカルでのテストもサポートしています。",[21,605,608],{"href":606,"rel":607},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fja_jp\u002Fserverless-application-model\u002Flatest\u002Fdeveloperguide\u002Fserverless-sam-cli-install-linux.html#serverless-sam-cli-install-linux-docker",[25],"テストではDockerを用いることがドキュメントにも書かれています。",[11,610,611,612,615,616,619,620,623],{},"LambdaのコードはDockerのあるコンテナにて実行されることになります。そのため、",[39,613,614],{},"localhost:8000","というのは私のホストOSの8000ポートでなく、SAMが実行されている環境の8000ポートに向いていたのです。SAMコンテナ内の",[39,617,618],{},"locahost:8000","にはDynamoDBなんてありませんから、",[39,621,622],{},"Inaccessible host"," になるのは当たり前です。",[11,625,626],{},"つまりやることはSAMコンテナネットワークと、DynamoDBコンテナネットワークを接続してあげる必要があります。",[597,628,630],{"id":629},"dynamodbの設定とテスト実行時の引数を与える","DynamoDBの設定とテスト実行時の引数を与える",[11,632,633],{},"先ほどのDynamoDBのdocker-compose.yamlを見てみると、ネットワークの設定があります。",[32,635,637],{"className":58,"code":636,"filename":60,"language":61,"meta":41,"style":41},"version: \"3\"\n\nservices:\n  dynamodb-local:\n    container_name: dynamodb-local\n    image: amazon\u002Fdynamodb-local\n    ports:\n      - 8000:8000\n    command: -jar DynamoDBLocal.jar -dbPath \u002Fdata -sharedDb\n    volumes:\n      - .\u002Fdata:\u002Fdata\n    networks:\n      - lambda-local\nnetworks:\n  lambda-local:\n    external: true #これ！\n",[39,638,639,651,655,661,667,675,683,689,695,703,709,715,721,727,733,739],{"__ignoreMap":41},[65,640,641,643,645,647,649],{"class":67,"line":68},[65,642,72],{"class":71},[65,644,76],{"class":75},[65,646,79],{"class":75},[65,648,83],{"class":82},[65,650,86],{"class":75},[65,652,653],{"class":67,"line":89},[65,654,93],{"emptyLinePlaceholder":92},[65,656,657,659],{"class":67,"line":96},[65,658,99],{"class":71},[65,660,102],{"class":75},[65,662,663,665],{"class":67,"line":105},[65,664,108],{"class":71},[65,666,102],{"class":75},[65,668,669,671,673],{"class":67,"line":113},[65,670,116],{"class":71},[65,672,76],{"class":75},[65,674,121],{"class":82},[65,676,677,679,681],{"class":67,"line":124},[65,678,127],{"class":71},[65,680,76],{"class":75},[65,682,132],{"class":82},[65,684,685,687],{"class":67,"line":135},[65,686,138],{"class":71},[65,688,102],{"class":75},[65,690,691,693],{"class":67,"line":143},[65,692,146],{"class":75},[65,694,149],{"class":82},[65,696,697,699,701],{"class":67,"line":152},[65,698,155],{"class":71},[65,700,76],{"class":75},[65,702,160],{"class":82},[65,704,705,707],{"class":67,"line":163},[65,706,166],{"class":71},[65,708,102],{"class":75},[65,710,711,713],{"class":67,"line":171},[65,712,146],{"class":75},[65,714,176],{"class":82},[65,716,717,719],{"class":67,"line":179},[65,718,182],{"class":71},[65,720,102],{"class":75},[65,722,723,725],{"class":67,"line":187},[65,724,146],{"class":75},[65,726,192],{"class":82},[65,728,729,731],{"class":67,"line":195},[65,730,198],{"class":71},[65,732,102],{"class":75},[65,734,735,737],{"class":67,"line":203},[65,736,206],{"class":71},[65,738,102],{"class":75},[65,740,741,743,745,748],{"class":67,"line":211},[65,742,214],{"class":71},[65,744,76],{"class":75},[65,746,747],{"class":219}," true",[65,749,751],{"class":750},"sC9rS"," #これ！\n",[11,753,754],{},"そしてSAMコンテナの立ち上げの際、このネットワークに接続できる引数があります。",[32,756,759],{"className":757,"code":758,"language":37},[35],"sam local invoke -e events\u002Fevent.json --docker-network lambda-local\n",[39,760,758],{"__ignoreMap":41},[11,762,763,766],{},[39,764,765],{},"--docker-network lambda-local"," を指定することで、DynamoDBコンテナのネットワークにアクセスできるようになります。そしてホストも以下のように書き換えます。",[32,768,770],{"className":234,"code":769,"filename":236,"language":237,"meta":41,"style":41},"var dynamoOpt = {\n    endpoint: \"http:\u002F\u002Fdynamodb-local:8000\",\n};\n",[39,771,772,782,797],{"__ignoreMap":41},[65,773,774,776,778,780],{"class":67,"line":68},[65,775,290],{"class":244},[65,777,293],{"class":248},[65,779,252],{"class":75},[65,781,298],{"class":75},[65,783,784,786,788,790,793,795],{"class":67,"line":89},[65,785,303],{"class":71},[65,787,76],{"class":75},[65,789,79],{"class":75},[65,791,792],{"class":82},"http:\u002F\u002Fdynamodb-local:8000",[65,794,313],{"class":75},[65,796,316],{"class":75},[65,798,799],{"class":67,"line":96},[65,800,321],{"class":75},[11,802,803],{},"実際のコードではホスト部分は環境変数に置き換えます。とりあえず上記ホストに変更して、もう一度先ほどのコマンドを実行しました。結果、なんとかDynamoDBに接続してCRUD操作ができるようになりました。",[11,805,806],{},"複数のコンテナを立てていたりすると、どこがどう繋がっているか分からなくなるので結構はまりました。汗）",[808,809,810],"style",{},"html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}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 pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":41,"searchDepth":96,"depth":96,"links":812},[813,814],{"id":51,"depth":89,"text":52},{"id":592,"depth":89,"text":592,"children":815},[816,817],{"id":599,"depth":96,"text":600},{"id":629,"depth":96,"text":630},[819],"ministack","2026-05-07","AWS SAMとDynamoDBの接続","md",null,{},"\u002Farticles\u002Faws-sam-disconnect-dymamodb-local",{"title":6,"description":821},"articles\u002Faws-sam-disconnect-dymamodb-local",[829,830,831],"aws","docker","serverless","util\u002Fsam_squirrel.png","wCqQZ02-pnfwd_-TA9YeBhfjRe0nMADGHPc1dk6e2z0",{"id":835,"title":836,"body":837,"category":2187,"createdAt":2189,"description":2190,"extension":822,"index":823,"meta":2191,"navigation":92,"path":2192,"publish":92,"seo":2193,"series":823,"seriesTitle":823,"stem":2194,"tag":2195,"thumbnail":2196,"updatedAt":2189,"__hash__":2197},"articles\u002Farticles\u002Fmultiple-select-vue.md","multiple属性での複数選択セレクトボックスで選択した値をemitする方法。",{"type":8,"value":838,"toc":2181},[839,842,845,848,865,983,1004,1007,1350,1357,1364,1368,1371,1379,1491,1502,1507,1510,1514,1518,1521,1993,1999,2005,2014,2080,2097,2154,2163,2166,2169,2172,2175,2178],[11,840,841],{},"こんにちはjunです。vue.jsを用いてフォームUIを作成していたところmultipule属性を付与したセレクトボックスで選択した値を$emitする方法についてメモ＆共有しようと思います。",[49,843,844],{"id":844},"vueを用いてselectの値を受け取る",[11,846,847],{},"セレクトボックスは基本的には以下の様に、プルダウン式のメニューから一つの値を選ぶ要素です。",[849,850,852,853,852,858,852,862],"select",{"name":851},"sample","\n ",[854,855,857],"option",{"value":856},"1","選択肢１",[854,859,861],{"value":860},"2","選択肢2",[854,863,864],{"value":83},"選択肢3",[32,866,870],{"className":867,"code":868,"language":869,"meta":41,"style":41},"language-html shiki shiki-themes material-theme-ocean","\u003Cselect name=\"sample\">\n \u003Coption value=\"1\">選択肢１\u003C\u002Foption>\n \u003Coption value=\"2\">選択肢2\u003C\u002Foption>\n \u003Coption value=\"3\">選択肢3\u003C\u002Foption>\n\u003C\u002Fselect>\n","html",[39,871,872,893,923,949,975],{"__ignoreMap":41},[65,873,874,877,879,882,884,886,888,890],{"class":67,"line":68},[65,875,876],{"class":75},"\u003C",[65,878,849],{"class":71},[65,880,881],{"class":244}," name",[65,883,252],{"class":75},[65,885,313],{"class":75},[65,887,851],{"class":82},[65,889,313],{"class":75},[65,891,892],{"class":75},">\n",[65,894,895,898,900,903,905,907,909,911,914,916,919,921],{"class":67,"line":89},[65,896,897],{"class":75}," \u003C",[65,899,854],{"class":71},[65,901,902],{"class":244}," value",[65,904,252],{"class":75},[65,906,313],{"class":75},[65,908,856],{"class":82},[65,910,313],{"class":75},[65,912,913],{"class":75},">",[65,915,857],{"class":248},[65,917,918],{"class":75},"\u003C\u002F",[65,920,854],{"class":71},[65,922,892],{"class":75},[65,924,925,927,929,931,933,935,937,939,941,943,945,947],{"class":67,"line":96},[65,926,897],{"class":75},[65,928,854],{"class":71},[65,930,902],{"class":244},[65,932,252],{"class":75},[65,934,313],{"class":75},[65,936,860],{"class":82},[65,938,313],{"class":75},[65,940,913],{"class":75},[65,942,861],{"class":248},[65,944,918],{"class":75},[65,946,854],{"class":71},[65,948,892],{"class":75},[65,950,951,953,955,957,959,961,963,965,967,969,971,973],{"class":67,"line":105},[65,952,897],{"class":75},[65,954,854],{"class":71},[65,956,902],{"class":244},[65,958,252],{"class":75},[65,960,313],{"class":75},[65,962,83],{"class":82},[65,964,313],{"class":75},[65,966,913],{"class":75},[65,968,864],{"class":248},[65,970,918],{"class":75},[65,972,854],{"class":71},[65,974,892],{"class":75},[65,976,977,979,981],{"class":67,"line":113},[65,978,918],{"class":75},[65,980,849],{"class":71},[65,982,892],{"class":75},[11,984,985,986,989,990,992,993,995,996,999,1000,1003],{},"基本的にinput系の値を取得するときは",[39,987,988],{},"v-model","を使用するのが定石ですが、",[39,991,988],{},"では解決できないコンポーネントの状況もあるでしょう。私も",[39,994,988],{},"という糖衣構文ではなく",[39,997,998],{},"v-bind=\"~~~\"",", ",[39,1001,1002],{},"@input=\"$emit(~~~~)\"","という形で入力された値を親コンポーネントに返す様にしていました。",[11,1005,1006],{},"一択のセレクトボックスであれば以下の様に記述できます。",[32,1008,1012],{"className":1009,"code":1010,"language":1011,"meta":41,"style":41},"language-vue shiki shiki-themes material-theme-ocean","\u003Ctemplate>\n \u003Cselect name=\"postName\" @input=\"$emit('newInput', $event.target.value)\">\n   \u003Coption v-for=\"val in selectBox\"\n           :value=\"val.value\" \n           :selected=\"inputValue === val.value\">\n           {{val.text}}\n   \u003C\u002Foption>\n \u003C\u002Fselect>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default{\n name:'childSelect',\n props:['inputed'],  \u002F\u002F親コンポーネントから初期値のvalueを受け取るためのprops\n data(){\n   return{\n     selector:[\n          {text:'選択肢1',value:'1'},\n          {text:'選択肢2',value:'2'},\n          {text:'選択肢3',value:'3'}\n     ],\n   }\n },\n \n}\n\u003C\u002Fscript>\n","vue",[39,1013,1014,1023,1054,1073,1090,1106,1111,1120,1129,1137,1141,1150,1160,1176,1201,1211,1218,1228,1260,1288,1316,1323,1328,1333,1337,1341],{"__ignoreMap":41},[65,1015,1016,1018,1021],{"class":67,"line":68},[65,1017,876],{"class":75},[65,1019,1020],{"class":71},"template",[65,1022,892],{"class":75},[65,1024,1025,1027,1029,1031,1033,1035,1038,1040,1043,1045,1047,1050,1052],{"class":67,"line":89},[65,1026,897],{"class":75},[65,1028,849],{"class":71},[65,1030,881],{"class":244},[65,1032,252],{"class":75},[65,1034,313],{"class":75},[65,1036,1037],{"class":82},"postName",[65,1039,313],{"class":75},[65,1041,1042],{"class":244}," @input",[65,1044,252],{"class":75},[65,1046,313],{"class":75},[65,1048,1049],{"class":82},"$emit('newInput', $event.target.value)",[65,1051,313],{"class":75},[65,1053,892],{"class":75},[65,1055,1056,1059,1061,1064,1066,1068,1071],{"class":67,"line":96},[65,1057,1058],{"class":75},"   \u003C",[65,1060,854],{"class":71},[65,1062,1063],{"class":244}," v-for",[65,1065,252],{"class":75},[65,1067,313],{"class":75},[65,1069,1070],{"class":82},"val in selectBox",[65,1072,86],{"class":75},[65,1074,1075,1078,1080,1082,1085,1087],{"class":67,"line":105},[65,1076,1077],{"class":244},"           :value",[65,1079,252],{"class":75},[65,1081,313],{"class":75},[65,1083,1084],{"class":82},"val.value",[65,1086,313],{"class":75},[65,1088,1089],{"class":75}," \n",[65,1091,1092,1095,1097,1099,1102,1104],{"class":67,"line":113},[65,1093,1094],{"class":244},"           :selected",[65,1096,252],{"class":75},[65,1098,313],{"class":75},[65,1100,1101],{"class":82},"inputValue === val.value",[65,1103,313],{"class":75},[65,1105,892],{"class":75},[65,1107,1108],{"class":67,"line":124},[65,1109,1110],{"class":248},"           {{val.text}}\n",[65,1112,1113,1116,1118],{"class":67,"line":135},[65,1114,1115],{"class":75},"   \u003C\u002F",[65,1117,854],{"class":71},[65,1119,892],{"class":75},[65,1121,1122,1125,1127],{"class":67,"line":143},[65,1123,1124],{"class":75}," \u003C\u002F",[65,1126,849],{"class":71},[65,1128,892],{"class":75},[65,1130,1131,1133,1135],{"class":67,"line":152},[65,1132,918],{"class":75},[65,1134,1020],{"class":71},[65,1136,892],{"class":75},[65,1138,1139],{"class":67,"line":163},[65,1140,93],{"emptyLinePlaceholder":92},[65,1142,1143,1145,1148],{"class":67,"line":171},[65,1144,876],{"class":75},[65,1146,1147],{"class":71},"script",[65,1149,892],{"class":75},[65,1151,1152,1155,1158],{"class":67,"line":179},[65,1153,1154],{"class":244},"export",[65,1156,1157],{"class":402}," default",[65,1159,406],{"class":75},[65,1161,1162,1165,1167,1169,1172,1174],{"class":67,"line":187},[65,1163,881],{"class":1164},"s5Dmg",[65,1166,76],{"class":75},[65,1168,262],{"class":75},[65,1170,1171],{"class":82},"childSelect",[65,1173,262],{"class":75},[65,1175,316],{"class":75},[65,1177,1178,1181,1183,1186,1188,1191,1193,1196,1198],{"class":67,"line":195},[65,1179,1180],{"class":1164}," props",[65,1182,76],{"class":75},[65,1184,1185],{"class":71},"[",[65,1187,262],{"class":75},[65,1189,1190],{"class":82},"inputed",[65,1192,262],{"class":75},[65,1194,1195],{"class":71},"]",[65,1197,349],{"class":75},[65,1199,1200],{"class":750},"  \u002F\u002F親コンポーネントから初期値のvalueを受け取るためのprops\n",[65,1202,1203,1206,1209],{"class":67,"line":203},[65,1204,1205],{"class":255}," data",[65,1207,1208],{"class":71},"()",[65,1210,406],{"class":75},[65,1212,1213,1216],{"class":67,"line":211},[65,1214,1215],{"class":402},"   return",[65,1217,406],{"class":75},[65,1219,1220,1223,1225],{"class":67,"line":466},[65,1221,1222],{"class":71},"     selector",[65,1224,76],{"class":75},[65,1226,1227],{"class":71},"[\n",[65,1229,1230,1233,1235,1237,1239,1242,1244,1246,1249,1251,1253,1255,1257],{"class":67,"line":496},[65,1231,1232],{"class":75},"          {",[65,1234,37],{"class":71},[65,1236,76],{"class":75},[65,1238,262],{"class":75},[65,1240,1241],{"class":82},"選択肢1",[65,1243,262],{"class":75},[65,1245,349],{"class":75},[65,1247,1248],{"class":71},"value",[65,1250,76],{"class":75},[65,1252,262],{"class":75},[65,1254,856],{"class":82},[65,1256,262],{"class":75},[65,1258,1259],{"class":75},"},\n",[65,1261,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280,1282,1284,1286],{"class":67,"line":502},[65,1263,1232],{"class":75},[65,1265,37],{"class":71},[65,1267,76],{"class":75},[65,1269,262],{"class":75},[65,1271,861],{"class":82},[65,1273,262],{"class":75},[65,1275,349],{"class":75},[65,1277,1248],{"class":71},[65,1279,76],{"class":75},[65,1281,262],{"class":75},[65,1283,860],{"class":82},[65,1285,262],{"class":75},[65,1287,1259],{"class":75},[65,1289,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314],{"class":67,"line":520},[65,1291,1232],{"class":75},[65,1293,37],{"class":71},[65,1295,76],{"class":75},[65,1297,262],{"class":75},[65,1299,864],{"class":82},[65,1301,262],{"class":75},[65,1303,349],{"class":75},[65,1305,1248],{"class":71},[65,1307,76],{"class":75},[65,1309,262],{"class":75},[65,1311,83],{"class":82},[65,1313,262],{"class":75},[65,1315,570],{"class":75},[65,1317,1318,1321],{"class":67,"line":527},[65,1319,1320],{"class":71},"     ]",[65,1322,316],{"class":75},[65,1324,1325],{"class":67,"line":539},[65,1326,1327],{"class":75},"   }\n",[65,1329,1330],{"class":67,"line":556},[65,1331,1332],{"class":75}," },\n",[65,1334,1335],{"class":67,"line":561},[65,1336,1089],{"class":71},[65,1338,1339],{"class":67,"line":567},[65,1340,570],{"class":75},[65,1342,1344,1346,1348],{"class":67,"line":1343},26,[65,1345,918],{"class":75},[65,1347,1147],{"class":71},[65,1349,892],{"class":75},[11,1351,1352,1353,1356],{},"この様にすることで親コンポーネントでは",[39,1354,1355],{},"newInput","を用いてこのセレクトボックスからの値を受け取ることができます。",[11,1358,1359,1360,1363],{},"もし編集画面など、セレクトボックスに予め選択済みの設定を行う場合はpropsにvalueの値を入れておけば、一致する選択肢に",[39,1361,1362],{},"selected","が付与されます。",[49,1365,1367],{"id":1366},"multipuleで複数選択を可能にする","Multipuleで複数選択を可能にする",[11,1369,1370],{},"チェックボックスにしては値が多く、リストの方が見やすいのでセレクトボックスから複数選択ができる様にするためには、multipleという属性を付与するだけで実装できます。",[849,1372,852,1373,852,1375,852,1377],{"name":851,"multiple":92},[854,1374,857],{"value":856},[854,1376,861],{"value":860},[854,1378,864],{"value":83},[32,1380,1382],{"className":867,"code":1381,"language":869,"meta":41,"style":41},"\u003Cselect name=\"sample\" multiple>\n \u003Coption value=\"1\">選択肢１\u003C\u002Foption>\n \u003Coption value=\"2\">選択肢2\u003C\u002Foption>\n \u003Coption value=\"3\">選択肢3\u003C\u002Foption>\n\u003C\u002Fselect>\n",[39,1383,1384,1405,1431,1457,1483],{"__ignoreMap":41},[65,1385,1386,1388,1390,1392,1394,1396,1398,1400,1403],{"class":67,"line":68},[65,1387,876],{"class":75},[65,1389,849],{"class":71},[65,1391,881],{"class":244},[65,1393,252],{"class":75},[65,1395,313],{"class":75},[65,1397,851],{"class":82},[65,1399,313],{"class":75},[65,1401,1402],{"class":244}," multiple",[65,1404,892],{"class":75},[65,1406,1407,1409,1411,1413,1415,1417,1419,1421,1423,1425,1427,1429],{"class":67,"line":89},[65,1408,897],{"class":75},[65,1410,854],{"class":71},[65,1412,902],{"class":244},[65,1414,252],{"class":75},[65,1416,313],{"class":75},[65,1418,856],{"class":82},[65,1420,313],{"class":75},[65,1422,913],{"class":75},[65,1424,857],{"class":248},[65,1426,918],{"class":75},[65,1428,854],{"class":71},[65,1430,892],{"class":75},[65,1432,1433,1435,1437,1439,1441,1443,1445,1447,1449,1451,1453,1455],{"class":67,"line":96},[65,1434,897],{"class":75},[65,1436,854],{"class":71},[65,1438,902],{"class":244},[65,1440,252],{"class":75},[65,1442,313],{"class":75},[65,1444,860],{"class":82},[65,1446,313],{"class":75},[65,1448,913],{"class":75},[65,1450,861],{"class":248},[65,1452,918],{"class":75},[65,1454,854],{"class":71},[65,1456,892],{"class":75},[65,1458,1459,1461,1463,1465,1467,1469,1471,1473,1475,1477,1479,1481],{"class":67,"line":105},[65,1460,897],{"class":75},[65,1462,854],{"class":71},[65,1464,902],{"class":244},[65,1466,252],{"class":75},[65,1468,313],{"class":75},[65,1470,83],{"class":82},[65,1472,313],{"class":75},[65,1474,913],{"class":75},[65,1476,864],{"class":248},[65,1478,918],{"class":75},[65,1480,854],{"class":71},[65,1482,892],{"class":75},[65,1484,1485,1487,1489],{"class":67,"line":113},[65,1486,918],{"class":75},[65,1488,849],{"class":71},[65,1490,892],{"class":75},[11,1492,1493,1494,1497,1498,1501],{},"実際に",[39,1495,1496],{},"$event.target.value","を",[39,1499,1500],{},"console.log()","で出力して見てみると、選択肢１をクリックしてから他の選択肢も含めましたが帰って来た結果は全て「１」でした。",[1503,1504],"image-render",{":src":1505,":width":1506},"'_mix\u002Fvue-select03-768x197.png'","'100%'",[11,1508,1509],{},"格納する親コンポーネントのdataもこの様に１から変化ありませんでした。",[1503,1511],{":src":1512,":width":1513},"'_mix\u002Fvue-select04.png'","'400px'",[49,1515,1517],{"id":1516},"multipleの場合はeventtargetoptions","multipleの場合は$event.target.options",[11,1519,1520],{},"選択された値は全て配列で帰ってくる様に調整をします。inputされた時、以下の様に値を取得する様に変更します。",[32,1522,1524],{"className":1009,"code":1523,"language":1011,"meta":41,"style":41},"\u003Ctemplate>\n \u003Cselect name=\"postName\" @input=\"returnValeu($event)\" multiple>\n   \u003Coption v-for=\"val in selectBox\"\n           :value=\"val.value\" \n           :selected=\"inputValue === val.value\">\n           {{val.text}}\n   \u003C\u002Foption>\n \u003C\u002Fselect>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default{\n name:'childSelect',\n props:['inputed'],  \u002F\u002F親コンポーネントから初期値のvalueを受け取るためのprops\n methods:{\n  returnValeu($event){\n    let opt = Object.values($event.target.options).filter(ele=>{\n                  return ele.selected;\n              })\n    let values = opt.map(ele=>ele.value);\n    this.$emit('newInput', values);\n  }\n }\n data(){\n   return{\n     selector:[\n          {text:'選択肢1',value:'1'},\n          {text:'選択肢2',value:'2'},\n          {text:'選択肢3',value:'3'}\n     ],\n   }\n },\n \n}\n\u003C\u002Fscript>\n",[39,1525,1526,1534,1565,1581,1595,1609,1613,1621,1629,1637,1641,1649,1657,1671,1691,1699,1713,1761,1775,1782,1814,1838,1843,1848,1856,1862,1870,1899,1928,1957,1964,1969,1974,1979,1984],{"__ignoreMap":41},[65,1527,1528,1530,1532],{"class":67,"line":68},[65,1529,876],{"class":75},[65,1531,1020],{"class":71},[65,1533,892],{"class":75},[65,1535,1536,1538,1540,1542,1544,1546,1548,1550,1552,1554,1556,1559,1561,1563],{"class":67,"line":89},[65,1537,897],{"class":75},[65,1539,849],{"class":71},[65,1541,881],{"class":244},[65,1543,252],{"class":75},[65,1545,313],{"class":75},[65,1547,1037],{"class":82},[65,1549,313],{"class":75},[65,1551,1042],{"class":244},[65,1553,252],{"class":75},[65,1555,313],{"class":75},[65,1557,1558],{"class":82},"returnValeu($event)",[65,1560,313],{"class":75},[65,1562,1402],{"class":244},[65,1564,892],{"class":75},[65,1566,1567,1569,1571,1573,1575,1577,1579],{"class":67,"line":96},[65,1568,1058],{"class":75},[65,1570,854],{"class":71},[65,1572,1063],{"class":244},[65,1574,252],{"class":75},[65,1576,313],{"class":75},[65,1578,1070],{"class":82},[65,1580,86],{"class":75},[65,1582,1583,1585,1587,1589,1591,1593],{"class":67,"line":105},[65,1584,1077],{"class":244},[65,1586,252],{"class":75},[65,1588,313],{"class":75},[65,1590,1084],{"class":82},[65,1592,313],{"class":75},[65,1594,1089],{"class":75},[65,1596,1597,1599,1601,1603,1605,1607],{"class":67,"line":113},[65,1598,1094],{"class":244},[65,1600,252],{"class":75},[65,1602,313],{"class":75},[65,1604,1101],{"class":82},[65,1606,313],{"class":75},[65,1608,892],{"class":75},[65,1610,1611],{"class":67,"line":124},[65,1612,1110],{"class":248},[65,1614,1615,1617,1619],{"class":67,"line":135},[65,1616,1115],{"class":75},[65,1618,854],{"class":71},[65,1620,892],{"class":75},[65,1622,1623,1625,1627],{"class":67,"line":143},[65,1624,1124],{"class":75},[65,1626,849],{"class":71},[65,1628,892],{"class":75},[65,1630,1631,1633,1635],{"class":67,"line":152},[65,1632,918],{"class":75},[65,1634,1020],{"class":71},[65,1636,892],{"class":75},[65,1638,1639],{"class":67,"line":163},[65,1640,93],{"emptyLinePlaceholder":92},[65,1642,1643,1645,1647],{"class":67,"line":171},[65,1644,876],{"class":75},[65,1646,1147],{"class":71},[65,1648,892],{"class":75},[65,1650,1651,1653,1655],{"class":67,"line":179},[65,1652,1154],{"class":244},[65,1654,1157],{"class":402},[65,1656,406],{"class":75},[65,1658,1659,1661,1663,1665,1667,1669],{"class":67,"line":187},[65,1660,881],{"class":1164},[65,1662,76],{"class":75},[65,1664,262],{"class":75},[65,1666,1171],{"class":82},[65,1668,262],{"class":75},[65,1670,316],{"class":75},[65,1672,1673,1675,1677,1679,1681,1683,1685,1687,1689],{"class":67,"line":195},[65,1674,1180],{"class":1164},[65,1676,76],{"class":75},[65,1678,1185],{"class":71},[65,1680,262],{"class":75},[65,1682,1190],{"class":82},[65,1684,262],{"class":75},[65,1686,1195],{"class":71},[65,1688,349],{"class":75},[65,1690,1200],{"class":750},[65,1692,1693,1696],{"class":67,"line":203},[65,1694,1695],{"class":1164}," methods",[65,1697,1698],{"class":75},":{\n",[65,1700,1701,1704,1706,1709,1711],{"class":67,"line":211},[65,1702,1703],{"class":255},"  returnValeu",[65,1705,259],{"class":71},[65,1707,1708],{"class":248},"$event",[65,1710,355],{"class":71},[65,1712,406],{"class":75},[65,1714,1715,1717,1720,1722,1725,1727,1730,1732,1734,1736,1739,1741,1744,1746,1748,1751,1753,1756,1759],{"class":67,"line":466},[65,1716,365],{"class":244},[65,1718,1719],{"class":248}," opt",[65,1721,336],{"class":75},[65,1723,1724],{"class":248}," Object",[65,1726,425],{"class":75},[65,1728,1729],{"class":255},"values",[65,1731,259],{"class":71},[65,1733,1708],{"class":248},[65,1735,425],{"class":75},[65,1737,1738],{"class":248},"target",[65,1740,425],{"class":75},[65,1742,1743],{"class":248},"options",[65,1745,355],{"class":71},[65,1747,425],{"class":75},[65,1749,1750],{"class":255},"filter",[65,1752,259],{"class":71},[65,1754,1755],{"class":345},"ele",[65,1757,1758],{"class":244},"=>",[65,1760,406],{"class":75},[65,1762,1763,1766,1769,1771,1773],{"class":67,"line":496},[65,1764,1765],{"class":402},"                  return",[65,1767,1768],{"class":248}," ele",[65,1770,425],{"class":75},[65,1772,1362],{"class":248},[65,1774,281],{"class":75},[65,1776,1777,1780],{"class":67,"line":502},[65,1778,1779],{"class":75},"              }",[65,1781,270],{"class":71},[65,1783,1784,1786,1789,1791,1793,1795,1798,1800,1802,1804,1806,1808,1810,1812],{"class":67,"line":520},[65,1785,365],{"class":244},[65,1787,1788],{"class":248}," values",[65,1790,336],{"class":75},[65,1792,1719],{"class":248},[65,1794,425],{"class":75},[65,1796,1797],{"class":255},"map",[65,1799,259],{"class":71},[65,1801,1755],{"class":345},[65,1803,1758],{"class":244},[65,1805,1755],{"class":248},[65,1807,425],{"class":75},[65,1809,1248],{"class":248},[65,1811,355],{"class":71},[65,1813,281],{"class":75},[65,1815,1816,1819,1822,1824,1826,1828,1830,1832,1834,1836],{"class":67,"line":527},[65,1817,1818],{"class":75},"    this.",[65,1820,1821],{"class":255},"$emit",[65,1823,259],{"class":71},[65,1825,262],{"class":75},[65,1827,1355],{"class":82},[65,1829,262],{"class":75},[65,1831,349],{"class":75},[65,1833,1788],{"class":248},[65,1835,355],{"class":71},[65,1837,281],{"class":75},[65,1839,1840],{"class":67,"line":539},[65,1841,1842],{"class":75},"  }\n",[65,1844,1845],{"class":67,"line":556},[65,1846,1847],{"class":75}," }\n",[65,1849,1850,1852,1854],{"class":67,"line":561},[65,1851,1205],{"class":255},[65,1853,1208],{"class":71},[65,1855,406],{"class":75},[65,1857,1858,1860],{"class":67,"line":567},[65,1859,1215],{"class":402},[65,1861,406],{"class":75},[65,1863,1864,1866,1868],{"class":67,"line":1343},[65,1865,1222],{"class":71},[65,1867,76],{"class":75},[65,1869,1227],{"class":71},[65,1871,1873,1875,1877,1879,1881,1883,1885,1887,1889,1891,1893,1895,1897],{"class":67,"line":1872},27,[65,1874,1232],{"class":75},[65,1876,37],{"class":71},[65,1878,76],{"class":75},[65,1880,262],{"class":75},[65,1882,1241],{"class":82},[65,1884,262],{"class":75},[65,1886,349],{"class":75},[65,1888,1248],{"class":71},[65,1890,76],{"class":75},[65,1892,262],{"class":75},[65,1894,856],{"class":82},[65,1896,262],{"class":75},[65,1898,1259],{"class":75},[65,1900,1902,1904,1906,1908,1910,1912,1914,1916,1918,1920,1922,1924,1926],{"class":67,"line":1901},28,[65,1903,1232],{"class":75},[65,1905,37],{"class":71},[65,1907,76],{"class":75},[65,1909,262],{"class":75},[65,1911,861],{"class":82},[65,1913,262],{"class":75},[65,1915,349],{"class":75},[65,1917,1248],{"class":71},[65,1919,76],{"class":75},[65,1921,262],{"class":75},[65,1923,860],{"class":82},[65,1925,262],{"class":75},[65,1927,1259],{"class":75},[65,1929,1931,1933,1935,1937,1939,1941,1943,1945,1947,1949,1951,1953,1955],{"class":67,"line":1930},29,[65,1932,1232],{"class":75},[65,1934,37],{"class":71},[65,1936,76],{"class":75},[65,1938,262],{"class":75},[65,1940,864],{"class":82},[65,1942,262],{"class":75},[65,1944,349],{"class":75},[65,1946,1248],{"class":71},[65,1948,76],{"class":75},[65,1950,262],{"class":75},[65,1952,83],{"class":82},[65,1954,262],{"class":75},[65,1956,570],{"class":75},[65,1958,1960,1962],{"class":67,"line":1959},30,[65,1961,1320],{"class":71},[65,1963,316],{"class":75},[65,1965,1967],{"class":67,"line":1966},31,[65,1968,1327],{"class":75},[65,1970,1972],{"class":67,"line":1971},32,[65,1973,1332],{"class":75},[65,1975,1977],{"class":67,"line":1976},33,[65,1978,1089],{"class":71},[65,1980,1982],{"class":67,"line":1981},34,[65,1983,570],{"class":75},[65,1985,1987,1989,1991],{"class":67,"line":1986},35,[65,1988,918],{"class":75},[65,1990,1147],{"class":71},[65,1992,892],{"class":75},[11,1994,1995,1996,1998],{},"処理が少し長めなのでmethodに切り分けました。",[39,1997,1558],{},"の中身で、イベント（選択）が発生したターゲットの要素を捉えるまでは同じですが、その中にvalueではなくてoptionsというプロパティがあります。",[11,2000,2001,2004],{},[39,2002,2003],{},"$event.target.options","は配列ですがHTMLCollectionなのでObject.valuesをもちいて、filter()が使用できる様にしています。",[11,2006,2007,2009,2010,2013],{},[39,2008,2003],{},"には選択肢の",[39,2011,2012],{},"\u003Coption>\u003C\u002Foption>","部分に関する情報が入っており、選択されたか（selected）とその値（value）というプロパティがあります。",[32,2015,2019],{"className":2016,"code":2017,"language":2018,"meta":41,"style":41},"language-javascript shiki shiki-themes material-theme-ocean","let opt = Object.values($event.target.options).filter(ele=>{\n　　return ele.selected;\n})\n","javascript",[39,2020,2021,2060,2073],{"__ignoreMap":41},[65,2022,2023,2025,2028,2030,2032,2034,2036,2039,2041,2043,2045,2048,2050,2052,2054,2056,2058],{"class":67,"line":68},[65,2024,275],{"class":244},[65,2026,2027],{"class":248}," opt ",[65,2029,252],{"class":75},[65,2031,1724],{"class":248},[65,2033,425],{"class":75},[65,2035,1729],{"class":255},[65,2037,2038],{"class":248},"($event",[65,2040,425],{"class":75},[65,2042,1738],{"class":248},[65,2044,425],{"class":75},[65,2046,2047],{"class":248},"options)",[65,2049,425],{"class":75},[65,2051,1750],{"class":255},[65,2053,259],{"class":248},[65,2055,1755],{"class":345},[65,2057,1758],{"class":244},[65,2059,406],{"class":75},[65,2061,2062,2065,2067,2069,2071],{"class":67,"line":89},[65,2063,2064],{"class":402},"　　return",[65,2066,1768],{"class":248},[65,2068,425],{"class":75},[65,2070,1362],{"class":248},[65,2072,281],{"class":75},[65,2074,2075,2078],{"class":67,"line":96},[65,2076,2077],{"class":75},"}",[65,2079,270],{"class":248},[11,2081,2082,2083,2085,2086,2089,2090,2093,2094,2096],{},"ここで",[39,2084,1362],{},"プロパティが",[39,2087,2088],{},"true","か",[39,2091,2092],{},"false","で選択されたかがわかるので、",[39,2095,2088],{},"の要素のみ取得して新しい配列を手に入れます。その配列に対して",[32,2098,2100],{"className":2016,"code":2099,"language":2018,"meta":41,"style":41},"let values = opt.map(ele=>ele.value);\nthis.$emit('newInput', values);\n",[39,2101,2102,2132],{"__ignoreMap":41},[65,2103,2104,2106,2109,2111,2113,2115,2117,2119,2121,2123,2125,2127,2130],{"class":67,"line":68},[65,2105,275],{"class":244},[65,2107,2108],{"class":248}," values ",[65,2110,252],{"class":75},[65,2112,1719],{"class":248},[65,2114,425],{"class":75},[65,2116,1797],{"class":255},[65,2118,259],{"class":248},[65,2120,1755],{"class":345},[65,2122,1758],{"class":244},[65,2124,1755],{"class":248},[65,2126,425],{"class":75},[65,2128,2129],{"class":248},"value)",[65,2131,281],{"class":75},[65,2133,2134,2137,2139,2141,2143,2145,2147,2149,2152],{"class":67,"line":89},[65,2135,2136],{"class":75},"this.",[65,2138,1821],{"class":255},[65,2140,259],{"class":248},[65,2142,262],{"class":75},[65,2144,1355],{"class":82},[65,2146,262],{"class":75},[65,2148,349],{"class":75},[65,2150,2151],{"class":248}," values)",[65,2153,281],{"class":75},[11,2155,2156,2159,2160,2162],{},[39,2157,2158],{},"map()","を用いて",[39,2161,1248],{},"プロパティのみを抽出したものを新しい配列として返し、それを親コンポーネントに渡します。これで選択したものを配列として渡すことが可能になります。",[49,2164,2165],{"id":2165},"値を出力してみる",[11,2167,2168],{},"先ほどの様に選択肢１から順に選択して値の変化を見てみましょう。",[1503,2170],{":src":2171,":width":1513},"'_mix\u002Fvue-select06-768x203-2.png'",[1503,2173],{":src":2174,":width":1513},"'_mix\u002Fvue-select05-1.png'",[11,2176,2177],{},"取得された値が順番順番に配列で取得できてますね。親コンポーネントにもちゃんと入っています。これでmultipule属性を持ったセレクトボックスの値を$emitすることができます。",[808,2179,2180],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}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 pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}",{"title":41,"searchDepth":96,"depth":96,"links":2182},[2183,2184,2185,2186],{"id":844,"depth":89,"text":844},{"id":1366,"depth":89,"text":1367},{"id":1516,"depth":89,"text":1517},{"id":2165,"depth":89,"text":2165},[2188],"devstack","2026-04-15","multiple属性での複数選択セレクトボックスで選択した値をemitする方法",{},"\u002Farticles\u002Fmultiple-select-vue",{"title":836,"description":2190},"articles\u002Fmultiple-select-vue",[237,1011],"_mix\u002Fvue-select06-768x203.png","VP5RFAbgJFA3otr_esQFmbFyOCNxilN184p7o6oAQZo",{"id":2199,"title":2200,"body":2201,"category":2774,"createdAt":2775,"description":2200,"extension":822,"index":823,"meta":2776,"navigation":92,"path":2777,"publish":92,"seo":2778,"series":823,"seriesTitle":823,"stem":2779,"tag":2780,"thumbnail":823,"updatedAt":2775,"__hash__":2783},"articles\u002Farticles\u002Fconnect-with-scp-ssh.md","FTPクライアントでなくターミナルでsshやscpによる通信を行う方法",{"type":8,"value":2202,"toc":2737},[2203,2206,2209,2212,2215,2218,2221,2227,2237,2242,2253,2256,2259,2263,2273,2282,2286,2289,2292,2295,2298,2301,2304,2308,2311,2314,2322,2325,2328,2331,2334,2336,2339,2342,2345,2348,2351,2354,2357,2360,2363,2366,2369,2372,2378,2384,2387,2393,2400,2403,2406,2412,2415,2418,2424,2427,2430,2436,2439,2442,2445,2457,2460,2463,2466,2469,2475,2478,2484,2487,2493,2496,2500,2503,2506,2509,2512,2518,2521,2524,2530,2537,2543,2546,2550,2553,2559,2562,2565,2568,2571,2577,2580,2584,2587,2590,2596,2599,2605,2608,2614,2617,2620,2623,2626,2629,2635,2638,2644,2647,2651,2657,2661,2667,2671,2674,2680,2686,2689,2692,2698,2701,2704,2710,2716,2719,2722,2728,2731,2734],[11,2204,2205],{},"こんにちはjunです。あなたはサーバー上にファイルをアップロードする際にどうやっていますか？大体がFTPクライアント（windowsだとwinscp、MacだとFileZillaなど）を使用していると思います。",[11,2207,2208],{},"GUIで操作できるソフトは扱いやすく、簡単にアップロード・ダウンロードを行ったり、複数ファイルを移動する際などは便利です。しかしある程度エンジニアレベルが上がると、サーバー構築やサーバー上での操作、例えば権限のいるファイルの編集とか機械的なファイル操作が必要になってくるので、FTPクライアントでの操作では限界が生じます。",[11,2210,2211],{},"特に大量のファイルを扱う際にはGUIクライアントソフトを用いると時間がかかったりすることも多かったり、権限によってファイルの操作ができない場合はsudoを打てる環境を用意しないといけません。",[11,2213,2214],{},"今回の記事ではSSHでサーバーとのやりとりをするための設定、そしてローカルとリモート間のscpを用いたファイル転送などGUIからCLI操作へのステップアップできるように解説していきたいと思います",[49,2216,2217],{"id":2217},"前提条件",[11,2219,2220],{},"細かい説明に入る前に以下の条件での説明とします。",[11,2222,2223],{},[2224,2225,2226],"strong",{},"クライアント",[2228,2229,2230,2234],"ul",{},[2231,2232,2233],"li",{},"macOS Catalina 10.15.5",[2231,2235,2236],{},"ターミナルを使用",[11,2238,2239],{},[2224,2240,2241],{},"サーバー（GMO VPSとします）",[2228,2243,2244,2247,2250],{},[2231,2245,2246],{},"centOS7",[2231,2248,2249],{},"22番ポート開放済み",[2231,2251,2252],{},"sshdインストール済み",[49,2254,2255],{"id":2255},"用語や基礎知識の確認",[11,2257,2258],{},"まず以降の説明を行う前に基礎的な用語と知識の解説を行います。知っている人はフンフンと頷きながら飛ばしてください。",[597,2260,2262],{"id":2261},"ssh","SSH",[11,2264,2265,2268,2269,2272],{},[2224,2266,2267],{},"S","ecure ",[2224,2270,2271],{},"Sh","ellのこと。直訳すると「安全なシェル」。シェルというのはターミナルとかコマンドプロンプトのことだと思ってください。そのシェルとネットワークを用いて遠隔にあるサーバーを操作します。昔はTelnetというものを用いてシェルで遠隔操作していましたが、Telnetで送受信するデータが平文という脆弱性がありました。",[11,2274,2275,2276,2278,2279,2281],{},"それに対する形で通信内容が暗号化される様になっているのがSSH。だから",[2224,2277,2267],{},"ecure な ",[2224,2280,2271],{},"ellと言われる。HttpにHttpsがついた様なニュアンス。",[597,2283,2285],{"id":2284},"ipアドレス","IPアドレス",[11,2287,2288],{},"ネットワーク通信を行うえで必要な、各ネットワーク機器を一意に区別する数字のこと。マイナンバーとか車のナンバーみたいなものです。IPを用いることで接続するサーバーを指定することができます。SSHでは接続先のIPを知る必要があります。",[597,2290,2291],{"id":2291},"ユーザー",[11,2293,2294],{},"サーバー上で操作するための名前というか、操作者の名前です。ユーザーを複数作り権限を割り振ることでサーバー上の操作を制限することができます。個々の名前にしておけば、誰が何を実行したのかも分かります。SSHでは「どのユーザー（権限を持った人）で実行するか？」が大切になります。",[11,2296,2297],{},"linuxでは「root」という名前のユーザーが最初にいます。このrootは他人のパスワードも変えられるし、サーバー上全てのファイルを消すことなんて可能な、なんでもできる「スーパーユーザー」です。",[597,2299,2300],{"id":2300},"グループ",[11,2302,2303],{},"ユーザーをくくる為の「組」のこと。そのままの意味です。同じグループ内であれば所有者が異なるファイルであっても操作ができます。（そのような権限が付与されている場合）",[597,2305,2307],{"id":2306},"ssh認証方式","SSH認証方式",[11,2309,2310],{},"SSHはリモートでサーバーに接続しますが、サーバーからしてみれば「どこのよく分からないIP（あなたのPC）から自分をいじってもいいか？」と聞かれているので必ず認証をします。つまりこのサーバーをいじっても良い正規の人間かをチェックします。",[11,2312,2313],{},"その認証方式としてSSHでは主に",[2228,2315,2316,2319],{},[2231,2317,2318],{},"パスワード認証方式",[2231,2320,2321],{},"鍵交換方式",[11,2323,2324],{},"の２つがあります。",[2326,2327,2318],"h4",{"id":2318},[11,2329,2330],{},"接続する際のユーザー名と、そのユーザーに紐づいたパスワードで接続することができます。Webサービスでログインがあるものと同じですね。分かりやすいですが、接続の度にパスワードを求められてちょっと面倒です。",[11,2332,2333],{},"また総当たり攻撃で突破される可能性もあるので、運用とセキュリティ面では次の鍵交換がおすすめです。",[2326,2335,2321],{"id":2321},[11,2337,2338],{},"秘密鍵と公開鍵というものを用いて認証を行います。鍵交換による認証原理の説明は今回は省きます。秘密鍵をクライアント（ローカル）において、公開鍵をサーバーにおいておきます。",[11,2340,2341],{},"ユーザーに紐づいた秘密鍵・公開鍵で認証を行います。秘密鍵は後述する通りにコマンドのオプションで指定できるので自動化やSSHの簡略化の際に便利になります。また秘密鍵のファイルが外部に漏れなければパスワード方式より安全です。",[11,2343,2344],{},"今回の解説では鍵交換方式でのSSH実行方法の設定も行います。",[49,2346,2347],{"id":2347},"接続準備",[11,2349,2350],{},"今回は自分でVPSを借りて接続をするという状況として操作をします。ConohaやGMOではブラウザから最初にサーバーの設定を行います。",[11,2352,2353],{},"OSやrootユーザーのパスワードを設定してまず、サーバーが作られます。IPアドレスなども管理画面などに表示されていると思いますので控えておきます。",[11,2355,2356],{},"IPアドレスは「123.456.789.012」の様なピリオド４つで分けられた数字列のことです。",[1503,2358],{":src":2359,":width":1506},"'_mix\u002Fconoha-768x714.png'",[1503,2361],{":src":2362,":width":1506},"'_mix\u002Fxserver-768x432.png'",[597,2364,2365],{"id":2365},"接続自体は簡単",[11,2367,2368],{},"IPアドレスとSSHユーザー名とパスワードがわかればあとは簡単です。とりあえず今回はVPSを借りているという想定なので、そのVPSのIPとrootユーザーパスワードがわかっているとします。",[11,2370,2371],{},"macならばターミナルを開きます。macにはsshを行うsshdが入っているので以下のコマンドを唱えます。",[32,2373,2376],{"className":2374,"code":2375,"language":37},[35],"~ % ssh root@IP_ADRESS\n",[39,2377,2375],{"__ignoreMap":41},[11,2379,2380,2383],{},[39,2381,2382],{},"ssh ユーザー名＠IPアドレス","を入力します。これは「指定したIPアドレスにrootというユーザー名でssh接続します！」という意味です。特にオプションを指定せず、パスワード認証方式が許可されている場合はパスワードを聞いてくるので入力します。",[11,2385,2386],{},"正しくパスワードを入力すると次の様な文章が出てきます。",[32,2388,2391],{"className":2389,"code":2390,"language":37},[35],"The authenticity of host '*****************' can't be established.\nRSA key fingerprint is *****************.\nAre you sure you want to continue connecting (yes\u002Fno)? \n>yes #問題なければ\n",[39,2392,2390],{"__ignoreMap":41},[11,2394,2395,2396,2399],{},"これはSSHキーフィンガースプリントと言われ日本語では「鍵指紋」と言われています。簡単に説明すると指定したIPで接続しても「本当に自分が繋ごうとしてるサーバーであっていますか？」と尋ねてくる。基本的にVPSなどは信頼できるので",[39,2397,2398],{},"yes","を選択。",[11,2401,2402],{},"この時yesを押すとクライアント側にサーバーから送られた公開鍵のハッシュ が保存されます。次回以降の接続ではこの公開鍵のハッシュが一緒に認証に使用されます。なぜ一緒に使われるのかというと、サーバーのなりすまし防止です。",[11,2404,2405],{},"IPなどの情報に加えてさらにsshdサーバーを区別するためにこの情報を保存して、接続先を担保します。もし次回に保存した公開鍵とサーバーから提示された公開鍵ハッシュ が異なると以下の様な警告が出ます。",[32,2407,2410],{"className":2408,"code":2409,"language":37},[35],"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\nIT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n",[39,2411,2409],{"__ignoreMap":41},[49,2413,2414],{"id":2414},"接続の確認",[11,2416,2417],{},"認証が終えるとこれでssh完了です。意外と簡単ですよね。変わったかどうかを確かめるには、とりあえずターミナルの表示を確認してみてください。",[32,2419,2422],{"className":2420,"code":2421,"language":37},[35],"Last login: Wed Jul 15 18:11:06 2020 from xxxxxxxxxxxxx\n[root@HOST_NAME ~]$\n",[39,2423,2421],{"__ignoreMap":41},[11,2425,2426],{},"この様にログイン時間、そして左側の表記が「ユーザー名＠IPなどのホスト名　カレントディレクトリ名」になっています。この状態であればログインできています。",[11,2428,2429],{},"sshを止める場合には",[32,2431,2434],{"className":2432,"code":2433,"language":37},[35],"[root@HOST_NAME ~]$ exit\n",[39,2435,2433],{"__ignoreMap":41},[11,2437,2438],{},"と入力するとsshを終了(ログアウト)できます。",[49,2440,2441],{"id":2441},"鍵交換の実装",[11,2443,2444],{},"前述した通りパスワード認証はわかりやすいですが、逐一パスワードを入力したりするのは面倒ですし、自動化ができません。流出や総当たりの危険性があるので出来たら鍵交換方式に変えた方がスムーズです。",[2446,2447,2448,2451,2454],"ol",{},[2231,2449,2450],{},"ここではrootでパスワード認証して初めてssh接続をした。",[2231,2452,2453],{},"このサーバーにはsshの公開鍵も秘密鍵もねえ！",[2231,2455,2456],{},"root用の鍵交換認証を実装",[11,2458,2459],{},"という状況で鍵交換を実装したいと思います。",[597,2461,2462],{"id":2462},"秘密鍵と公開鍵を作成する",[11,2464,2465],{},"サーバーにログインした状態で秘密鍵と公開鍵を作成します。ユーザーのホーム ディレクトリには「.ssh」という隠しフォルダがあり、その中にssh用の鍵を格納します。",[11,2467,2468],{},"もしホームディレクトリに.sshディレクトリがない場合は作成します。今回は無かったとしましょう。",[32,2470,2473],{"className":2471,"code":2472,"language":37},[35],"[root@HOST_NAME ~]$ mkdir .ssh\n[root@HOST_NAME ~]$ chmod 700 ~\u002F.ssh \n",[39,2474,2472],{"__ignoreMap":41},[11,2476,2477],{},".sshディレクトリは権限を700にします。でないと鍵による接続ができません。その.sshに移動して以下のコマンドを唱えて両鍵を作成します。今回はパスフレーズ（追加のパスワード）はなしとします。パスフレーズを入れるとパスワード認証の様に逐一入力を求められてしまいます。",[32,2479,2482],{"className":2480,"code":2481,"language":37},[35],"[root@HOST_NAME .ssh]$ ssh-keygen -t rsa -f id_rsa #-fはファイル名を指定できる。\nEnter passphrase (empty for no passphrase): #←パスフレーズを入力。基本なしでもOK、その際はEnterをおす\nEnter same passphrase again: #←パスフレーズを再入力。基本なしの時はEnterをおす\nYour identification has been saved in \u002Froot\u002F.ssh\u002Fid_rsa.\nYour public key has been saved in \u002Froot\u002F.ssh\u002Fid_rsa.pub.\nThe key fingerprint is:\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx root@xxxxx\nThe key's randomart image is:\n+--[ RSA 2048]----+\n|                 |\n|       .         |\n|        o        |\n|oo     . .       |\n|*.. .   S .      |\n|+E o       .     |\n|=.o . .   .      |\n|.+ . o ...       |\n|*+.   ..+o       |\n+-----------------+\n[root@HOST_NAME .ssh]$ ls\n[root@HOST_NAME .ssh]$ id_rsa id_rsa.pub\n",[39,2483,2481],{"__ignoreMap":41},[11,2485,2486],{},"鍵を作成してディレクトリ内をみると２つのファイルが見つかります。pubがついている方が公開鍵で、もう片方が秘密鍵です。次に公開鍵をサーバーに登録し、600権限を割り振ります。以下のコマンドを唱えます。",[32,2488,2491],{"className":2489,"code":2490,"language":37},[35],"[root@HOST_NAME .ssh]$ cat id_rsa.pub >> authorized_keys\n[root@HOST_NAME .ssh]$ chmod 600 authorized_keys\n[root@HOST_NAME .ssh]$ rm -fv id_rsa.pub #id_rsa.pubは捨てる\n",[39,2492,2490],{"__ignoreMap":41},[11,2494,2495],{},"権限の設定を忘れて接続ができないミスが多いので注意。",[49,2497,2499],{"id":2498},"秘密鍵をクライアント自分のpcへ送信","秘密鍵をクライアント（自分のPC）へ送信",[11,2501,2502],{},"では次に接続元となる自分のPCへサーバーで作成した秘密鍵id_rsaを送信します。.sshフォルダ以外の場所に移動して、クラアントツールでひっぱてもいいですが、せっかくなのでscpコマンドを用いてやってみましょう。",[2326,2504,2505],{"id":2505},"scpコマンドでリモートからコピーする",[11,2507,2508],{},"scpはGUIのソフトでの送受信の正体です。リモートからローカルへのファイルのコピーをします。ファイルをコピーするコマンドにcpがありますが、あれがネットワークを通じている物だと思ってください。",[11,2510,2511],{},"リモートからローカルへコピーする時はローカル側で以下のような入力をします。",[32,2513,2516],{"className":2514,"code":2515,"language":37},[35],"jun@MacBook-Pro% scp \u003Cユーザー名>@\u003CIPアドレス>:\u003Cファイルまでのパス> \u003Cファイルを置くローカルのパス>\n",[39,2517,2515],{"__ignoreMap":41},[11,2519,2520],{},"scpの後に１つ目に「コピー元のファイルまでのパス」、２つ目に「コピーしたファイルの置き場所」を入力します。注意して欲しいのはscpコマンドはサーバーにログインして唱えるのではないということです。",[11,2522,2523],{},"よくわからないと思うので、同じようにリモートからあるファイルを取得する操作をFileZillaで行うと以下のようにメッセージが表示されます。やっていることはscpと変わりません。",[32,2525,2528],{"className":2526,"code":2527,"language":37},[35],"状態:     \"\u002Fvar\u002Fwww\u002Fhtml\" のディレクトリ リストの表示成功\n状態:     xxx.xx.xxx.xxx に接続中...\n状態:     Using username \"sample\". \n状態:     Connected to    xxx.xx.xxx.xxx\n状態:     \u002Fvar\u002Fwww\u002Fhtml\u002Findex.php のダウンロードを開始しています\n状態:     42 バイト (1 秒) のファイル転送に成功しました\n",[39,2529,2527],{"__ignoreMap":41},[11,2531,2532,2533,2536],{},"ローカルからリモートへ接続してファイルを取得しているのがわかります。scpによるファイルの送受信は ",[2224,2534,2535],{},"サーバーにログインして行うのではなくて"," 、ローカル側から接続先を指定してファイルの送受信を行います。今回の秘密鍵を持ってくる場合は以下のように打ちます。",[32,2538,2541],{"className":2539,"code":2540,"language":37},[35],"jun@MacBook-Pro% scp root@IP_ADRESS:~\u002F.ssh\u002Fid_rsa ~\u002F\n",[39,2542,2540],{"__ignoreMap":41},[11,2544,2545],{},"「~\u002F」というのは「ホームディレクトリ」配下という意味です。「rootの ~\u002F.ssh\u002Fid_rsaにあるファイル」を「ローカルのホームディレクトリ 」にコピーしろ！という命令です。",[597,2547,2549],{"id":2548},"秘密鍵を適当な箇所に置いて権限を付与","秘密鍵を適当な箇所に置いて、権限を付与",[11,2551,2552],{},"秘密鍵は接続の際にパスで参照できればどこに置いてもいいのですが、わかりやすいようにローカルの.sshディレクトリ配下に入れることにします。Macにはホームディレクトリに.sshというssh用の隠しフォルダがあります。以下はローカルでの作業です。",[32,2554,2557],{"className":2555,"code":2556,"language":37},[35],"jun@MacBook-Pro % cd ~ #ホームディレクトリに移動\njun@MacBook-Pro ~ % mv id_rsa .ssh\u002F && cd .ssh\njun@MacBook-Pro .ssh % ls -a\nconfig  id_rsa  known_hosts\n\njun@MacBook-Pro .ssh % chmod 600 id_rsa\n",[39,2558,2556],{"__ignoreMap":41},[11,2560,2561],{},"ここでも秘密鍵は600権限を付与しておきます。ここも忘れてハマりやすいので注意。ssh接続先が多くなり、鍵が増えたら「keys」などの適当な鍵収納用のフォルダを作るといいです。",[49,2563,2564],{"id":2564},"鍵交換で接続する",[11,2566,2567],{},"以上で鍵交換の実装は完了です。実務的な運用の場合はサーバーでパスワードログインを禁止するなどが必要ですが今回は省略します。ではローカルから鍵を使ってログインしましょう。",[11,2569,2570],{},".ssh配下に鍵があるので、鍵のパスを指定しする様に以下の様に唱えます。",[32,2572,2575],{"className":2573,"code":2574,"language":37},[35],"jun@MacBook-Pro ~ % ssh -i ~\u002F.ssh\u002Fid_rsa root@IP_ADRESS\n",[39,2576,2574],{"__ignoreMap":41},[11,2578,2579],{},"パスワード式の接続に「-i」オプションを指定すると、「鍵交換で接続」という意味になります。-iの後にはローカルに保存した秘密鍵までのパスを指定します。あとはユーザー名とIPアドレスを入力すれば完了です。",[49,2581,2583],{"id":2582},"パス指定が面倒","パス指定が面倒〜〜",[11,2585,2586],{},"鍵交換で実装を行うとパスワードを入力しなくていいので、メモをみたり自動化の際には便利です。しかしパスの指定が面倒という欠点がありますが、簡単に解決できます。エイリアスを設定してとても簡単に接続できる様になります。",[11,2588,2589],{},"早速設定してみましょう。.sshディレクトリに移動して「config」というファイルを編集します。なければ作成してください。",[32,2591,2594],{"className":2592,"code":2593,"language":37},[35],"jun@MacBook-Pro ~ % cd ~\u002F.ssh\njun@MacBook-Pro .ssh % vi config\n",[39,2595,2593],{"__ignoreMap":41},[11,2597,2598],{},"このconfigファイルに以下の情報を登録します。",[32,2600,2603],{"className":2601,"code":2602,"language":37},[35],"Host sshconnect #好きな名前\n HostName IP_ADRESS\n User root\n Port 22\n IdentityFile ~\u002F.ssh\u002Fid_rsa\n",[39,2604,2602],{"__ignoreMap":41},[11,2606,2607],{},"configファイルに上記の様に記述すると以下のコマンドを唱えるだけで、HostNameで指定したサーバーへsshができます。",[32,2609,2612],{"className":2610,"code":2611,"language":37},[35],"jun@MacBook-Pro ~ % ssh sshconnect\n",[39,2613,2611],{"__ignoreMap":41},[11,2615,2616],{},"とっても短くになりました。「sshconnect」と入力しただけです。さらに鍵交換式なのでパスワードの入力も入りません。ちなみにユーザー名だけだと、パスワードが求められ入力しないといけません。セキュリティの関係上configファイルにはパスワードを記録できません。（FileZillaなどのソフトはソフト自身が記憶している）",[11,2618,2619],{},"完全にストレスフリーにHostのエイリアスを打つだけで接続するには鍵交換式しかできません。",[49,2621,2622],{"id":2622},"scpでファイルを送ってみよう",[11,2624,2625],{},"scpファイルの送受信をまとめておきます。",[597,2627,2628],{"id":2628},"エイリアスを用いた送受信",[32,2630,2633],{"className":2631,"code":2632,"language":37},[35],"jun@MacBook-Pro ~ %　scp ~\u002Ftest.txt sshconnect:~\u002F\n",[39,2634,2632],{"__ignoreMap":41},[11,2636,2637],{},"sshの接続先は上記の様にエイリアス化するとリモート先をこんなに簡単に接続できます。エイリアスを使わない場合は以下の様に唱えます。",[32,2639,2642],{"className":2640,"code":2641,"language":37},[35],"jun@MacBook-Pro ~ %　scp -i ~\u002F.ssh\u002Fid_rsa ~\u002Ftest.txt root@IP_ADRESS:~\u002F\n",[39,2643,2641],{"__ignoreMap":41},[11,2645,2646],{},"以下はエイリアスを用いた鍵交換となっています。",[49,2648,2650],{"id":2649},"ローカルリモート","ローカル→リモート",[32,2652,2655],{"className":2653,"code":2654,"language":37},[35],"jun@MacBook-Pro ~ %　scp ~\u002Ftest.txt sshconnect:~\u002F\n\n# scp \u003Cローカルのファイルまでのパス>　\u003Cエイリアス>:\u003Cリモートのコピー先のパス>\n",[39,2656,2654],{"__ignoreMap":41},[49,2658,2660],{"id":2659},"リモートローカル","リモート→ローカル",[32,2662,2665],{"className":2663,"code":2664,"language":37},[35],"jun@MacBook-Pro ~ %　scp sshconnect:~\u002Ftest.txt　~\u002F \n\n# scp \u003Cエイリアス>:\u003Cリモートのファイルまでのパス>　\u003Cローカルのコピー先のパス>\n",[39,2666,2664],{"__ignoreMap":41},[49,2668,2670],{"id":2669},"ディレクトリ-ごと移動ローカルから","ディレクトリ ごと移動（ローカルから）",[11,2672,2673],{},"膨大なファイルを輸送する時に早くて便利です。",[32,2675,2678],{"className":2676,"code":2677,"language":37},[35],"jun@MacBook-Pro ~ %　scp -r ~\u002Fheavy\u002F sshconnect:~\u002F\n",[39,2679,2677],{"__ignoreMap":41},[11,2681,2682,2685],{},[39,2683,2684],{},"-r","を指定しないと「送信するものが普通のファイルじゃないよ！（not a regular file）」と怒られます。再起的にコピーされるので、ディレクトリ配下全てがコピーされます。",[49,2687,2688],{"id":2688},"リモートからリモート",[11,2690,2691],{},"リモートサーバーその１をsshconnect01、その２をsshconnect02として01から02へ移動する場合です。ローカルを経由する方法と01で02に対するscpを行う方法があります。図示すると以下の様な感じです。",[32,2693,2696],{"className":2694,"code":2695,"language":37},[35],"ローカル経由\n\n  |-------sshconnect01\n  |↓   ←\nlocal\n  |↓　　→\n  |------sshconnect02\n\nリモートから直接\n  |-------sshconnect01\n  |↑   →       |↓\nlocal          |↓\n               |↓\n          sshconnect02\n",[39,2697,2695],{"__ignoreMap":41},[2326,2699,2700],{"id":2700},"リモートで直接",[11,2702,2703],{},"リモート01から02に直接送る場合はローカルで以下の様に打ちます",[32,2705,2708],{"className":2706,"code":2707,"language":37},[35],"リモート01から02に直接送る場合はローカルで以下の様に打ちます\n",[39,2709,2707],{"__ignoreMap":41},[11,2711,2712,2713,2715],{},"ディレクトリを写す場合は ",[39,2714,2684],{}," オプションを付けます。ただし、この方法は01は02への接続情報を持っていなければなりません。エリアスの場合も01の.ssh\u002Fconfigに sshconnect02についての記述を書く必要があります。02が鍵認証を行っている場合は01に02の鍵をおいておく必要があります。",[2326,2717,2718],{"id":2718},"ローカル経由",[11,2720,2721],{},"01から02に接続できない場合はローカルを経由する様にします。以下の様に打ちます。",[32,2723,2726],{"className":2724,"code":2725,"language":37},[35],"jun@MacBook-Pro ~ %　scp -3 sshconnect01:~\u002Ftest.txt　sshconnect02:~\u002F \n",[39,2727,2725],{"__ignoreMap":41},[11,2729,2730],{},"-3 オプションを使用します。ディレクトリコピーならばさらに -r を付けましょう。01からローカルに引っ張ってきてから、02へ送信します。自身の転送量は多くなりますが手軽にできます。",[49,2732,2733],{"id":2733},"あとがき",[11,2735,2736],{},"以上がsshによるリモートログインとscpによるファイル送受信方法です。いつもはGUIソフトで操作しつつ、大量のファイル移動や権限が伴う移動などはコマンドを用いた方が便利です。まずはtest.txtなど影響のないファイルを作って、練習するといいでしょう。",{"title":41,"searchDepth":96,"depth":96,"links":2738},[2739,2740,2750,2753,2754,2757,2761,2762,2763,2766,2767,2768,2769,2773],{"id":2217,"depth":89,"text":2217},{"id":2255,"depth":89,"text":2255,"children":2741},[2742,2743,2744,2745,2746],{"id":2261,"depth":96,"text":2262},{"id":2284,"depth":96,"text":2285},{"id":2291,"depth":96,"text":2291},{"id":2300,"depth":96,"text":2300},{"id":2306,"depth":96,"text":2307,"children":2747},[2748,2749],{"id":2318,"depth":105,"text":2318},{"id":2321,"depth":105,"text":2321},{"id":2347,"depth":89,"text":2347,"children":2751},[2752],{"id":2365,"depth":96,"text":2365},{"id":2414,"depth":89,"text":2414},{"id":2441,"depth":89,"text":2441,"children":2755},[2756],{"id":2462,"depth":96,"text":2462},{"id":2498,"depth":89,"text":2499,"children":2758},[2759,2760],{"id":2505,"depth":105,"text":2505},{"id":2548,"depth":96,"text":2549},{"id":2564,"depth":89,"text":2564},{"id":2582,"depth":89,"text":2583},{"id":2622,"depth":89,"text":2622,"children":2764},[2765],{"id":2628,"depth":96,"text":2628},{"id":2649,"depth":89,"text":2650},{"id":2659,"depth":89,"text":2660},{"id":2669,"depth":89,"text":2670},{"id":2688,"depth":89,"text":2688,"children":2770},[2771,2772],{"id":2700,"depth":105,"text":2700},{"id":2718,"depth":105,"text":2718},{"id":2733,"depth":89,"text":2733},[2188],"2026-03-25",{},"\u002Farticles\u002Fconnect-with-scp-ssh",{"title":2200,"description":2200},"articles\u002Fconnect-with-scp-ssh",[2781,2782],"infrastructure","network","vb0ciWoDxv7wsXMgPxZsPl_2qDz-iNYzIyU8cFy07oc",{"id":2785,"title":2786,"body":2787,"category":6859,"createdAt":6860,"description":2786,"extension":822,"index":823,"meta":6861,"navigation":92,"path":6862,"publish":92,"seo":6863,"series":823,"seriesTitle":823,"stem":6864,"tag":6865,"thumbnail":6866,"updatedAt":6860,"__hash__":6867},"articles\u002Farticles\u002Fjs-canvas-wave.md","画像下部が波でうねるアニメーションをcanvasで実装する",{"type":8,"value":2788,"toc":6836},[2789,2792,2795,2803,2806,2809,2823,2826,2829,2832,2835,2838,2841,2858,2861,2865,2868,2871,2874,2884,2887,3155,3158,3161,3164,3454,3457,3516,3519,3715,3726,3739,3742,3746,3750,3758,3819,3822,3825,3850,3853,3920,3926,3933,3939,3942,3945,3951,4633,4636,4647,4650,4654,4765,4771,4775,4781,5097,5100,5120,5123,5126,5130,5198,5210,5216,5218,5221,5224,5227,5427,5430,5433,5447,5450,5464,5467,5470,5473,5511,5520,5530,5533,5535,5538,5548,5657,5667,5677,5717,5720,5723,6735,6738,6741,6810,6827,6830,6833],[11,2790,2791],{},"こんにちはjunです。今日は以下のようなcanvasを用いたアニメーションを作っていきます。\nレスポンシブをとりあえず画像の一部をうねらせるだけであれば70行ほどのjsコードですみます。",[1503,2793],{":src":2794,":width":1506},"'_mix\u002Fex01-768x299.png'",[11,2796,2797,2802],{},[21,2798,2801],{"href":2799,"rel":2800},"https:\u002F\u002Fapps.jun-app.com\u002Fwave\u002F",[25],"こちら","にて実際に動かしています。",[49,2804,2805],{"id":2805},"必要な知識",[11,2807,2808],{},"細かい実装の説明にうつる前に今回用いる必要な知識と原理について確認します。以下の知識にある程度知見がある人はすっ飛ばしてください。",[2228,2810,2811,2814,2817,2820],{},[2231,2812,2813],{},"canvas要素",[2231,2815,2816],{},"jsでcanvasを読み込む方法",[2231,2818,2819],{},"jsでcanvasに画像を設定する方法",[2231,2821,2822],{},"三角関数（超基礎）",[49,2824,2825],{"id":2825},"canvasでのアニメーションの原理",[11,2827,2828],{},"実装サイトでも見ていただいと思いますが、きちんとアニメーションをしておりまた、動画を流しているわけではありません。このアニメーションはcanvas要素というものをjsで操作することで実装ができます。",[11,2830,2831],{},"画像を波打たせる方法は普通のimgタグやdivでは難しいです。柔軟に簡単に実装するためにcanvasを用います。",[11,2833,2834],{},"このcanvasでのアニメーションは実は見えないスピードで「画像を消しては、再描画、消して、再描画…」というのを行っています。また描画する画像は下部を透明な波線で消してから描画しています。また波が連なり、流れるように見せるために三角関数を用いて波型に消す箇所を計算しています。",[11,2836,2837],{},"ちょっとわかりにくいにので図にしてみます。",[1503,2839],{":src":2840,":width":1506},"'_mix\u002Fwave01.jpeg'",[2228,2842,2843,2846,2849,2852,2855],{},[2231,2844,2845],{},"canvasでは上図のオレンジ点で示した様な描画地点を座標で指定します。（１）",[2231,2847,2848],{},"描画地点は数式を用いて指定できるので、波の部分は三角関数で座標を指定します。（２）",[2231,2850,2851],{},"そして画像の端にたどり着いたら元の描画いちに戻る様にします。（３、４）",[2231,2853,2854],{},"囲まれた部分の色などを指定できるので、透明化を行います。（５）",[2231,2856,2857],{},"そしてすぐに画像を元に戻して、１〜５を再度行う。",[11,2859,2860],{},"また１〜６を繰り返すたびにsni(θ)のθを増やしていけば毎回異なる波がうねる様に見えます。この様にして波のアニメーションを実装します。",[597,2862,2864],{"id":2863},"canvasって何","canvasって何？",[11,2866,2867],{},"canvasというのはHTML5で扱われる要素の一つであり、2次元図形・グラフィック・アニメーションをjavaScriptを用いて描画することができます。cssでは解決できない図形やアニメーションを実装することができます。数十年前だとflashが担っていたことをHTMLで行うような感じです。",[49,2869,2870],{"id":2870},"canvasに画像を表示させる",[11,2872,2873],{},"ではまずはうねらせる画像をcanvas要素に表示させるところまで行います。今回は同階層に",[2228,2875,2876,2879,2881],{},[2231,2877,2878],{},"index.html",[2231,2880,236],{},[2231,2882,2883],{},"sample.jpg",[11,2885,2886],{},"を用意しておきます。sample.jpgは縦横比１：２にトリミングをしておきます。では作っていきましょう。まずは以下のように適当にHTMLを作っておきます。",[32,2888,2890],{"className":867,"code":2889,"language":869,"meta":41,"style":41},"\u003C!DOCTYPE html>\n\u003Chtml>\n    \u003Chead>\n        \u003Cmeta charset=\"utf-8\">\n        \u003Ctitle>waving image\u003C\u002Ftitle>\n        \u003Cstyle>\n            *{\n                margin:0;\n                padding:0;\n            }\n            main{\n                background:rgb(240, 255, 255);;\n            }\n        \u003C\u002Fstyle>\n    \u003C\u002Fhead>\n    \u003Cbody>\n        \u003Cmain>\n            \u003Ccanvas id=\"canvas\">\u003C\u002Fcanvas>\n        \u003C\u002Fmain>\n        \u003Cscript src=\".\u002Fapp.js\">\u003C\u002Fscript>\n    \u003C\u002Fbody>\n\u003C\u002Fhtml>\n",[39,2891,2892,2905,2913,2923,2945,2963,2971,2978,2991,3002,3007,3014,3041,3045,3054,3063,3072,3081,3107,3115,3139,3147],{"__ignoreMap":41},[65,2893,2894,2897,2900,2903],{"class":67,"line":68},[65,2895,2896],{"class":75},"\u003C!",[65,2898,2899],{"class":71},"DOCTYPE",[65,2901,2902],{"class":244}," html",[65,2904,892],{"class":75},[65,2906,2907,2909,2911],{"class":67,"line":89},[65,2908,876],{"class":75},[65,2910,869],{"class":71},[65,2912,892],{"class":75},[65,2914,2915,2918,2921],{"class":67,"line":96},[65,2916,2917],{"class":75},"    \u003C",[65,2919,2920],{"class":71},"head",[65,2922,892],{"class":75},[65,2924,2925,2928,2931,2934,2936,2938,2941,2943],{"class":67,"line":105},[65,2926,2927],{"class":75},"        \u003C",[65,2929,2930],{"class":71},"meta",[65,2932,2933],{"class":244}," charset",[65,2935,252],{"class":75},[65,2937,313],{"class":75},[65,2939,2940],{"class":82},"utf-8",[65,2942,313],{"class":75},[65,2944,892],{"class":75},[65,2946,2947,2949,2952,2954,2957,2959,2961],{"class":67,"line":113},[65,2948,2927],{"class":75},[65,2950,2951],{"class":71},"title",[65,2953,913],{"class":75},[65,2955,2956],{"class":248},"waving image",[65,2958,918],{"class":75},[65,2960,2951],{"class":71},[65,2962,892],{"class":75},[65,2964,2965,2967,2969],{"class":67,"line":124},[65,2966,2927],{"class":75},[65,2968,808],{"class":71},[65,2970,892],{"class":75},[65,2972,2973,2976],{"class":67,"line":135},[65,2974,2975],{"class":1164},"            *",[65,2977,406],{"class":75},[65,2979,2980,2984,2986,2989],{"class":67,"line":143},[65,2981,2983],{"class":2982},"s6YsC","                margin",[65,2985,76],{"class":75},[65,2987,2988],{"class":460},"0",[65,2990,281],{"class":75},[65,2992,2993,2996,2998,3000],{"class":67,"line":152},[65,2994,2995],{"class":2982},"                padding",[65,2997,76],{"class":75},[65,2999,2988],{"class":460},[65,3001,281],{"class":75},[65,3003,3004],{"class":67,"line":163},[65,3005,3006],{"class":75},"            }\n",[65,3008,3009,3012],{"class":67,"line":171},[65,3010,3011],{"class":1164},"            main",[65,3013,406],{"class":75},[65,3015,3016,3019,3021,3024,3026,3029,3031,3034,3036,3038],{"class":67,"line":179},[65,3017,3018],{"class":2982},"                background",[65,3020,76],{"class":75},[65,3022,3023],{"class":255},"rgb",[65,3025,259],{"class":75},[65,3027,3028],{"class":460},"240",[65,3030,349],{"class":75},[65,3032,3033],{"class":460}," 255",[65,3035,349],{"class":75},[65,3037,3033],{"class":460},[65,3039,3040],{"class":75},");;\n",[65,3042,3043],{"class":67,"line":187},[65,3044,3006],{"class":75},[65,3046,3047,3050,3052],{"class":67,"line":195},[65,3048,3049],{"class":75},"        \u003C\u002F",[65,3051,808],{"class":71},[65,3053,892],{"class":75},[65,3055,3056,3059,3061],{"class":67,"line":203},[65,3057,3058],{"class":75},"    \u003C\u002F",[65,3060,2920],{"class":71},[65,3062,892],{"class":75},[65,3064,3065,3067,3070],{"class":67,"line":211},[65,3066,2917],{"class":75},[65,3068,3069],{"class":71},"body",[65,3071,892],{"class":75},[65,3073,3074,3076,3079],{"class":67,"line":466},[65,3075,2927],{"class":75},[65,3077,3078],{"class":71},"main",[65,3080,892],{"class":75},[65,3082,3083,3086,3089,3092,3094,3096,3098,3100,3103,3105],{"class":67,"line":496},[65,3084,3085],{"class":75},"            \u003C",[65,3087,3088],{"class":71},"canvas",[65,3090,3091],{"class":244}," id",[65,3093,252],{"class":75},[65,3095,313],{"class":75},[65,3097,3088],{"class":82},[65,3099,313],{"class":75},[65,3101,3102],{"class":75},">\u003C\u002F",[65,3104,3088],{"class":71},[65,3106,892],{"class":75},[65,3108,3109,3111,3113],{"class":67,"line":502},[65,3110,3049],{"class":75},[65,3112,3078],{"class":71},[65,3114,892],{"class":75},[65,3116,3117,3119,3121,3124,3126,3128,3131,3133,3135,3137],{"class":67,"line":520},[65,3118,2927],{"class":75},[65,3120,1147],{"class":71},[65,3122,3123],{"class":244}," src",[65,3125,252],{"class":75},[65,3127,313],{"class":75},[65,3129,3130],{"class":82},".\u002Fapp.js",[65,3132,313],{"class":75},[65,3134,3102],{"class":75},[65,3136,1147],{"class":71},[65,3138,892],{"class":75},[65,3140,3141,3143,3145],{"class":67,"line":527},[65,3142,3058],{"class":75},[65,3144,3069],{"class":71},[65,3146,892],{"class":75},[65,3148,3149,3151,3153],{"class":67,"line":539},[65,3150,918],{"class":75},[65,3152,869],{"class":71},[65,3154,892],{"class":75},[11,3156,3157],{},"描画がされるcanvasを用意して、javascriptで拾えるようにidをつけておきましょう。あとは描画を実行するjsファイルをcanvasより後に書いておきます。",[597,3159,3160],{"id":3160},"javascriptで描画対象のcanvasを設定",[11,3162,3163],{},"app.jsに以下のようにコードを書きます。",[32,3165,3167],{"className":2016,"code":3166,"language":2018,"meta":41,"style":41},"function initAnimation(){\n    var canvas = document.getElementById('canvas');\n    var ctx = canvas.getContext('2d');\n\n    var imagePath = ('.\u002Fsample.jpg');\n    var image = new Image();\n    image.src = imagePath;\n\n    canvas.width = Number(window.innerWidth);\n    canvas.height = Number(canvas.width\u002F2);\n    image.onload = function(){\n          ctx.drawImage(image,0,0,image.width,image.height,0,0,canvas.width,canvas.height);\n    }\n}\n",[39,3168,3169,3180,3210,3239,3243,3265,3284,3299,3303,3332,3362,3378,3445,3450],{"__ignoreMap":41},[65,3170,3171,3174,3177],{"class":67,"line":68},[65,3172,3173],{"class":244},"function",[65,3175,3176],{"class":255}," initAnimation",[65,3178,3179],{"class":75},"(){\n",[65,3181,3182,3185,3188,3190,3193,3195,3198,3200,3202,3204,3206,3208],{"class":67,"line":89},[65,3183,3184],{"class":244},"    var",[65,3186,3187],{"class":248}," canvas",[65,3189,336],{"class":75},[65,3191,3192],{"class":248}," document",[65,3194,425],{"class":75},[65,3196,3197],{"class":255},"getElementById",[65,3199,259],{"class":71},[65,3201,262],{"class":75},[65,3203,3088],{"class":82},[65,3205,262],{"class":75},[65,3207,355],{"class":71},[65,3209,281],{"class":75},[65,3211,3212,3214,3217,3219,3221,3223,3226,3228,3230,3233,3235,3237],{"class":67,"line":96},[65,3213,3184],{"class":244},[65,3215,3216],{"class":248}," ctx",[65,3218,336],{"class":75},[65,3220,3187],{"class":248},[65,3222,425],{"class":75},[65,3224,3225],{"class":255},"getContext",[65,3227,259],{"class":71},[65,3229,262],{"class":75},[65,3231,3232],{"class":82},"2d",[65,3234,262],{"class":75},[65,3236,355],{"class":71},[65,3238,281],{"class":75},[65,3240,3241],{"class":67,"line":105},[65,3242,93],{"emptyLinePlaceholder":92},[65,3244,3245,3247,3250,3252,3254,3256,3259,3261,3263],{"class":67,"line":113},[65,3246,3184],{"class":244},[65,3248,3249],{"class":248}," imagePath",[65,3251,336],{"class":75},[65,3253,342],{"class":71},[65,3255,262],{"class":75},[65,3257,3258],{"class":82},".\u002Fsample.jpg",[65,3260,262],{"class":75},[65,3262,355],{"class":71},[65,3264,281],{"class":75},[65,3266,3267,3269,3272,3274,3277,3280,3282],{"class":67,"line":124},[65,3268,3184],{"class":244},[65,3270,3271],{"class":248}," image",[65,3273,336],{"class":75},[65,3275,3276],{"class":75}," new",[65,3278,3279],{"class":255}," Image",[65,3281,1208],{"class":71},[65,3283,281],{"class":75},[65,3285,3286,3288,3290,3293,3295,3297],{"class":67,"line":135},[65,3287,127],{"class":248},[65,3289,425],{"class":75},[65,3291,3292],{"class":248},"src",[65,3294,336],{"class":75},[65,3296,3249],{"class":248},[65,3298,281],{"class":75},[65,3300,3301],{"class":67,"line":143},[65,3302,93],{"emptyLinePlaceholder":92},[65,3304,3305,3308,3310,3313,3315,3318,3320,3323,3325,3328,3330],{"class":67,"line":152},[65,3306,3307],{"class":248},"    canvas",[65,3309,425],{"class":75},[65,3311,3312],{"class":248},"width",[65,3314,336],{"class":75},[65,3316,3317],{"class":255}," Number",[65,3319,259],{"class":71},[65,3321,3322],{"class":248},"window",[65,3324,425],{"class":75},[65,3326,3327],{"class":248},"innerWidth",[65,3329,355],{"class":71},[65,3331,281],{"class":75},[65,3333,3334,3336,3338,3341,3343,3345,3347,3349,3351,3353,3356,3358,3360],{"class":67,"line":163},[65,3335,3307],{"class":248},[65,3337,425],{"class":75},[65,3339,3340],{"class":248},"height",[65,3342,336],{"class":75},[65,3344,3317],{"class":255},[65,3346,259],{"class":71},[65,3348,3088],{"class":248},[65,3350,425],{"class":75},[65,3352,3312],{"class":248},[65,3354,3355],{"class":75},"\u002F",[65,3357,860],{"class":460},[65,3359,355],{"class":71},[65,3361,281],{"class":75},[65,3363,3364,3366,3368,3371,3373,3376],{"class":67,"line":171},[65,3365,127],{"class":248},[65,3367,425],{"class":75},[65,3369,3370],{"class":255},"onload",[65,3372,336],{"class":75},[65,3374,3375],{"class":244}," function",[65,3377,3179],{"class":75},[65,3379,3380,3383,3385,3388,3390,3393,3395,3397,3399,3401,3403,3405,3407,3409,3411,3413,3415,3417,3419,3421,3423,3425,3427,3429,3431,3433,3435,3437,3439,3441,3443],{"class":67,"line":179},[65,3381,3382],{"class":248},"          ctx",[65,3384,425],{"class":75},[65,3386,3387],{"class":255},"drawImage",[65,3389,259],{"class":71},[65,3391,3392],{"class":248},"image",[65,3394,349],{"class":75},[65,3396,2988],{"class":460},[65,3398,349],{"class":75},[65,3400,2988],{"class":460},[65,3402,349],{"class":75},[65,3404,3392],{"class":248},[65,3406,425],{"class":75},[65,3408,3312],{"class":248},[65,3410,349],{"class":75},[65,3412,3392],{"class":248},[65,3414,425],{"class":75},[65,3416,3340],{"class":248},[65,3418,349],{"class":75},[65,3420,2988],{"class":460},[65,3422,349],{"class":75},[65,3424,2988],{"class":460},[65,3426,349],{"class":75},[65,3428,3088],{"class":248},[65,3430,425],{"class":75},[65,3432,3312],{"class":248},[65,3434,349],{"class":75},[65,3436,3088],{"class":248},[65,3438,425],{"class":75},[65,3440,3340],{"class":248},[65,3442,355],{"class":71},[65,3444,281],{"class":75},[65,3446,3447],{"class":67,"line":187},[65,3448,3449],{"class":75},"    }\n",[65,3451,3452],{"class":67,"line":195},[65,3453,570],{"class":75},[11,3455,3456],{},"この箇所ではHTMLからcanvas要素を指定して、jsを用いてcanvasの操作を行える様にするおまじないです。以降はこのctx(描画コンテキストインスタンス)に様々な指定を行います。",[32,3458,3460],{"className":2016,"code":3459,"language":2018,"meta":41,"style":41},"var canvas = document.getElementById('canvas');\nvar ctx = canvas.getContext('2d');\n",[39,3461,3462,3489],{"__ignoreMap":41},[65,3463,3464,3466,3469,3471,3473,3475,3477,3479,3481,3483,3485,3487],{"class":67,"line":68},[65,3465,290],{"class":244},[65,3467,3468],{"class":248}," canvas ",[65,3470,252],{"class":75},[65,3472,3192],{"class":248},[65,3474,425],{"class":75},[65,3476,3197],{"class":255},[65,3478,259],{"class":248},[65,3480,262],{"class":75},[65,3482,3088],{"class":82},[65,3484,262],{"class":75},[65,3486,355],{"class":248},[65,3488,281],{"class":75},[65,3490,3491,3493,3496,3498,3500,3502,3504,3506,3508,3510,3512,3514],{"class":67,"line":89},[65,3492,290],{"class":244},[65,3494,3495],{"class":248}," ctx ",[65,3497,252],{"class":75},[65,3499,3187],{"class":248},[65,3501,425],{"class":75},[65,3503,3225],{"class":255},[65,3505,259],{"class":248},[65,3507,262],{"class":75},[65,3509,3232],{"class":82},[65,3511,262],{"class":75},[65,3513,355],{"class":248},[65,3515,281],{"class":75},[11,3517,3518],{},"そして",[32,3520,3522],{"className":2016,"code":3521,"language":2018,"meta":41,"style":41},"var imagePath = ('.\u002Fsample.jpg');\nvar image = new Image();\nimage.src = imagePath;\n\ncanvas.width = Number(window.innerWidth);\ncanvas.height = Number(canvas.width\u002F2);\nimage.onload = function(){\n        ctx.drawImage(image,0,0,image.width,image.height,0,0,canvas.width,canvas.height);\n}\n",[39,3523,3524,3545,3562,3577,3581,3604,3632,3646,3711],{"__ignoreMap":41},[65,3525,3526,3528,3531,3533,3535,3537,3539,3541,3543],{"class":67,"line":68},[65,3527,290],{"class":244},[65,3529,3530],{"class":248}," imagePath ",[65,3532,252],{"class":75},[65,3534,342],{"class":248},[65,3536,262],{"class":75},[65,3538,3258],{"class":82},[65,3540,262],{"class":75},[65,3542,355],{"class":248},[65,3544,281],{"class":75},[65,3546,3547,3549,3552,3554,3556,3558,3560],{"class":67,"line":89},[65,3548,290],{"class":244},[65,3550,3551],{"class":248}," image ",[65,3553,252],{"class":75},[65,3555,3276],{"class":75},[65,3557,3279],{"class":255},[65,3559,1208],{"class":248},[65,3561,281],{"class":75},[65,3563,3564,3566,3568,3571,3573,3575],{"class":67,"line":96},[65,3565,3392],{"class":248},[65,3567,425],{"class":75},[65,3569,3570],{"class":248},"src ",[65,3572,252],{"class":75},[65,3574,3249],{"class":248},[65,3576,281],{"class":75},[65,3578,3579],{"class":67,"line":105},[65,3580,93],{"emptyLinePlaceholder":92},[65,3582,3583,3585,3587,3590,3592,3594,3597,3599,3602],{"class":67,"line":113},[65,3584,3088],{"class":248},[65,3586,425],{"class":75},[65,3588,3589],{"class":248},"width ",[65,3591,252],{"class":75},[65,3593,3317],{"class":255},[65,3595,3596],{"class":248},"(window",[65,3598,425],{"class":75},[65,3600,3601],{"class":248},"innerWidth)",[65,3603,281],{"class":75},[65,3605,3606,3608,3610,3613,3615,3617,3620,3622,3624,3626,3628,3630],{"class":67,"line":124},[65,3607,3088],{"class":248},[65,3609,425],{"class":75},[65,3611,3612],{"class":248},"height ",[65,3614,252],{"class":75},[65,3616,3317],{"class":255},[65,3618,3619],{"class":248},"(canvas",[65,3621,425],{"class":75},[65,3623,3312],{"class":248},[65,3625,3355],{"class":75},[65,3627,860],{"class":460},[65,3629,355],{"class":248},[65,3631,281],{"class":75},[65,3633,3634,3636,3638,3640,3642,3644],{"class":67,"line":135},[65,3635,3392],{"class":248},[65,3637,425],{"class":75},[65,3639,3370],{"class":255},[65,3641,336],{"class":75},[65,3643,3375],{"class":244},[65,3645,3179],{"class":75},[65,3647,3648,3651,3653,3655,3657,3659,3661,3663,3665,3667,3669,3671,3673,3675,3677,3679,3681,3683,3685,3687,3689,3691,3693,3695,3697,3699,3701,3703,3705,3707,3709],{"class":67,"line":143},[65,3649,3650],{"class":248},"        ctx",[65,3652,425],{"class":75},[65,3654,3387],{"class":255},[65,3656,259],{"class":71},[65,3658,3392],{"class":248},[65,3660,349],{"class":75},[65,3662,2988],{"class":460},[65,3664,349],{"class":75},[65,3666,2988],{"class":460},[65,3668,349],{"class":75},[65,3670,3392],{"class":248},[65,3672,425],{"class":75},[65,3674,3312],{"class":248},[65,3676,349],{"class":75},[65,3678,3392],{"class":248},[65,3680,425],{"class":75},[65,3682,3340],{"class":248},[65,3684,349],{"class":75},[65,3686,2988],{"class":460},[65,3688,349],{"class":75},[65,3690,2988],{"class":460},[65,3692,349],{"class":75},[65,3694,3088],{"class":248},[65,3696,425],{"class":75},[65,3698,3312],{"class":248},[65,3700,349],{"class":75},[65,3702,3088],{"class":248},[65,3704,425],{"class":75},[65,3706,3340],{"class":248},[65,3708,355],{"class":71},[65,3710,281],{"class":75},[65,3712,3713],{"class":67,"line":152},[65,3714,570],{"class":75},[11,3716,3717,3718,3721,3722,3725],{},"jsのImageオブジェクトを用いてsrcプロパティに映す画像のパスを入れます。",[39,3719,3720],{},"canvas.width","、",[39,3723,3724],{},"canvas.height","でcanvasの大きさを指定します。画像が縦横１：２なので canvasもその比率に沿う様にしました。",[11,3727,3728,3731,3732,3735,3736,3738],{},[39,3729,3730],{},"image.onload"," を用いてsrcで指定した画像の読み込みが終わったら、\n",[39,3733,3734],{},"drawImage()"," メソッドを用いてcanvasに画像を描画する様にします。\n",[39,3737,3730],{}," を使わないと画像が読み込まれる前に描画しようとするので、映されません。",[11,3740,3741],{},"とりあえずここまでくると、canvas要素しかないHTMLにもかかわらず、以下の様に画像が描画されているはずです。",[1503,3743],{":src":3744,":width":3745,":center":2088},"'_mix\u002Fwave02.png'","'500px'",[2326,3747,3749],{"id":3748},"drawimageの使い方","drawImage()の使い方",[11,3751,3752,3753],{},"drawImage()はcanvasに範囲を指定して画像を描画します。canvas全体に画像を描画するならば必ず、最後の引数まで入力したほうがいいです。",[21,3754,3757],{"href":3755,"rel":3756},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FCanvasRenderingContext2D\u002FdrawImage",[25],"（MDNの解説（英語））",[32,3759,3761],{"className":2016,"code":3760,"language":2018,"meta":41,"style":41},"void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);\n",[39,3762,3763],{"__ignoreMap":41},[65,3764,3765,3768,3770,3772,3774,3777,3779,3782,3784,3787,3789,3792,3794,3797,3799,3802,3804,3807,3809,3812,3814,3817],{"class":67,"line":68},[65,3766,3767],{"class":75},"void",[65,3769,3216],{"class":248},[65,3771,425],{"class":75},[65,3773,3387],{"class":255},[65,3775,3776],{"class":248},"(image",[65,3778,349],{"class":75},[65,3780,3781],{"class":248}," sx",[65,3783,349],{"class":75},[65,3785,3786],{"class":248}," sy",[65,3788,349],{"class":75},[65,3790,3791],{"class":248}," sWidth",[65,3793,349],{"class":75},[65,3795,3796],{"class":248}," sHeight",[65,3798,349],{"class":75},[65,3800,3801],{"class":248}," dx",[65,3803,349],{"class":75},[65,3805,3806],{"class":248}," dy",[65,3808,349],{"class":75},[65,3810,3811],{"class":248}," dWidth",[65,3813,349],{"class":75},[65,3815,3816],{"class":248}," dHeight)",[65,3818,281],{"class":75},[11,3820,3821],{},"それぞれの引数を説明すると",[11,3823,3824],{},"Imageインスタンス。つまり描画する対象の画像",[2446,3826,3827,3830,3833,3836,3839,3842,3844,3847],{},[2231,3828,3829],{},"画像の切り抜き開始地点のX座標",[2231,3831,3832],{},"画像の切り抜き開始地点のY座標",[2231,3834,3835],{},"第２引数で指定したX座標から切り抜くX方向の距離（幅）",[2231,3837,3838],{},"第３引数で指定したY座標から切り抜くY方向の距離（高さ）",[2231,3840,3841],{},"canvasに描画する開始地点のX座標",[2231,3843,3841],{},[2231,3845,3846],{},"第６引数で指定したX座標から描画するX方向の距離（幅）",[2231,3848,3849],{},"第７引数で指定したY座標から描画するY方向の距離（高さ）",[11,3851,3852],{},"という感じです！私の今回の例でいくと",[32,3854,3856],{"className":2016,"code":3855,"language":2018,"meta":41,"style":41},"ctx.drawImage(image,0,0,image.width,image.height,0,0,canvas.width,canvas.height);\n",[39,3857,3858],{"__ignoreMap":41},[65,3859,3860,3863,3865,3867,3869,3871,3873,3875,3877,3879,3881,3883,3885,3887,3889,3891,3893,3895,3897,3899,3901,3903,3905,3907,3909,3911,3913,3915,3918],{"class":67,"line":68},[65,3861,3862],{"class":248},"ctx",[65,3864,425],{"class":75},[65,3866,3387],{"class":255},[65,3868,3776],{"class":248},[65,3870,349],{"class":75},[65,3872,2988],{"class":460},[65,3874,349],{"class":75},[65,3876,2988],{"class":460},[65,3878,349],{"class":75},[65,3880,3392],{"class":248},[65,3882,425],{"class":75},[65,3884,3312],{"class":248},[65,3886,349],{"class":75},[65,3888,3392],{"class":248},[65,3890,425],{"class":75},[65,3892,3340],{"class":248},[65,3894,349],{"class":75},[65,3896,2988],{"class":460},[65,3898,349],{"class":75},[65,3900,2988],{"class":460},[65,3902,349],{"class":75},[65,3904,3088],{"class":248},[65,3906,425],{"class":75},[65,3908,3312],{"class":248},[65,3910,349],{"class":75},[65,3912,3088],{"class":248},[65,3914,425],{"class":75},[65,3916,3917],{"class":248},"height)",[65,3919,281],{"class":75},[11,3921,3922,3925],{},[39,3923,3924],{},"0,0,image.width,image.height",", で画像の（０,０）座標地点から画像の幅と高さ分、画像を切り取るという意味です。つまり画像全体を読み取っているのと同じです。",[11,3927,3928,3929,3932],{},"もし",[39,3930,3931],{},"0,0,image.width\u002F2,image.height\u002F2",", としたら元画像の1\u002F4だけの部分切り取られた画像が映し出されます。",[11,3934,3935,3938],{},[39,3936,3937],{},"0,0,canvas.width,canvas.height"," ここもcanvasの（０,０）座標地点からcanvasの幅と高さ分、画像を貼り付けるという意味です。つまりcanvas全体に画像を貼り付けるのと同じです。",[11,3940,3941],{},"ここは実際にコードを描いて比率をいじって見てください。そうすればここの意味がわかる様になります。",[49,3943,3944],{"id":3944},"波線に画像を切り抜く",[11,3946,3947,3948,3950],{},"それでは次にこの画像を波線に切り抜きます。切り抜きのイメージとしては上で説明した図の様に、一辺が波線の四角形を描いて、透明に塗り潰します。",[39,3949,3730],{},"以降に以下のコードを加えます。",[32,3952,3954],{"className":2016,"code":3953,"language":2018,"meta":41,"style":41},"image.onload = function(){\n    initDraw();\n}\n    \nvar canvasEndX = canvas.width;\nvar canvasEndY = canvas.height;\nvar waveStartPoint = canvasEndY-150;\n\nvar amplitude = 30;\nvar period = 1000;\nvar degree = 0;\n\nfunction initDraw(){\n    imageSet(image,canvasEndX,canvasEndY);\n    waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);\n}\n\nfunction imageSet(imageObj,canvasEndX,canvasEndY){\n    var imgWidth = imageObj.width;\n    var imgHeight = imageObj.height;\n    ctx.drawImage(image,0,0,imgWidth,imgHeight,0,0,canvasEndX,canvasEndY);\n}\n\nfunction waveDrawing(waveStartPoint,canvasEndX,canvasEndY,deg,am,tp){\n    var waveStartY = waveStartPoint;\n    ctx.globalCompositeOperation = \"destination-out\";\n    ctx.beginPath();\n    ctx.moveTo(0, waveStartY);\n\n    for (var x=0; x \u003C= canvasEndX; x+= 1) {\n        var y = -am*Math.sin((Math.PI\u002Ftp)*(deg+x));\n        ctx.lineTo(x, y+waveStartY);\n    }\n\n    ctx.lineTo(canvasEndX,canvasEndY);\n    ctx.lineTo(0,canvasEndY);\n    ctx.closePath();\n\n    　ctx.fillStyle = \"rgba(255,255,255,1)\"; \u002F\u002Fopacity 1\n    ctx.fill();\n}\n",[39,3955,3956,3970,3979,3983,3988,4005,4022,4042,4046,4060,4074,4088,4092,4101,4124,4161,4165,4169,4192,4210,4227,4278,4282,4286,4322,4336,4356,4369,4390,4394,4436,4495,4521,4525,4529,4549,4570,4584,4589,4614,4628],{"__ignoreMap":41},[65,3957,3958,3960,3962,3964,3966,3968],{"class":67,"line":68},[65,3959,3392],{"class":248},[65,3961,425],{"class":75},[65,3963,3370],{"class":255},[65,3965,336],{"class":75},[65,3967,3375],{"class":244},[65,3969,3179],{"class":75},[65,3971,3972,3975,3977],{"class":67,"line":89},[65,3973,3974],{"class":255},"    initDraw",[65,3976,1208],{"class":71},[65,3978,281],{"class":75},[65,3980,3981],{"class":67,"line":96},[65,3982,570],{"class":75},[65,3984,3985],{"class":67,"line":105},[65,3986,3987],{"class":248},"    \n",[65,3989,3990,3992,3995,3997,3999,4001,4003],{"class":67,"line":113},[65,3991,290],{"class":244},[65,3993,3994],{"class":248}," canvasEndX ",[65,3996,252],{"class":75},[65,3998,3187],{"class":248},[65,4000,425],{"class":75},[65,4002,3312],{"class":248},[65,4004,281],{"class":75},[65,4006,4007,4009,4012,4014,4016,4018,4020],{"class":67,"line":124},[65,4008,290],{"class":244},[65,4010,4011],{"class":248}," canvasEndY ",[65,4013,252],{"class":75},[65,4015,3187],{"class":248},[65,4017,425],{"class":75},[65,4019,3340],{"class":248},[65,4021,281],{"class":75},[65,4023,4024,4026,4029,4031,4034,4037,4040],{"class":67,"line":135},[65,4025,290],{"class":244},[65,4027,4028],{"class":248}," waveStartPoint ",[65,4030,252],{"class":75},[65,4032,4033],{"class":248}," canvasEndY",[65,4035,4036],{"class":75},"-",[65,4038,4039],{"class":460},"150",[65,4041,281],{"class":75},[65,4043,4044],{"class":67,"line":143},[65,4045,93],{"emptyLinePlaceholder":92},[65,4047,4048,4050,4053,4055,4058],{"class":67,"line":152},[65,4049,290],{"class":244},[65,4051,4052],{"class":248}," amplitude ",[65,4054,252],{"class":75},[65,4056,4057],{"class":460}," 30",[65,4059,281],{"class":75},[65,4061,4062,4064,4067,4069,4072],{"class":67,"line":163},[65,4063,290],{"class":244},[65,4065,4066],{"class":248}," period ",[65,4068,252],{"class":75},[65,4070,4071],{"class":460}," 1000",[65,4073,281],{"class":75},[65,4075,4076,4078,4081,4083,4086],{"class":67,"line":171},[65,4077,290],{"class":244},[65,4079,4080],{"class":248}," degree ",[65,4082,252],{"class":75},[65,4084,4085],{"class":460}," 0",[65,4087,281],{"class":75},[65,4089,4090],{"class":67,"line":179},[65,4091,93],{"emptyLinePlaceholder":92},[65,4093,4094,4096,4099],{"class":67,"line":187},[65,4095,3173],{"class":244},[65,4097,4098],{"class":255}," initDraw",[65,4100,3179],{"class":75},[65,4102,4103,4106,4108,4110,4112,4115,4117,4120,4122],{"class":67,"line":195},[65,4104,4105],{"class":255},"    imageSet",[65,4107,259],{"class":71},[65,4109,3392],{"class":248},[65,4111,349],{"class":75},[65,4113,4114],{"class":248},"canvasEndX",[65,4116,349],{"class":75},[65,4118,4119],{"class":248},"canvasEndY",[65,4121,355],{"class":71},[65,4123,281],{"class":75},[65,4125,4126,4129,4131,4134,4136,4138,4140,4142,4144,4147,4149,4152,4154,4157,4159],{"class":67,"line":203},[65,4127,4128],{"class":255},"    waveDrawing",[65,4130,259],{"class":71},[65,4132,4133],{"class":248},"waveStartPoint",[65,4135,349],{"class":75},[65,4137,4114],{"class":248},[65,4139,349],{"class":75},[65,4141,4119],{"class":248},[65,4143,349],{"class":75},[65,4145,4146],{"class":248},"degree",[65,4148,349],{"class":75},[65,4150,4151],{"class":248},"amplitude",[65,4153,349],{"class":75},[65,4155,4156],{"class":248},"period",[65,4158,355],{"class":71},[65,4160,281],{"class":75},[65,4162,4163],{"class":67,"line":211},[65,4164,570],{"class":75},[65,4166,4167],{"class":67,"line":466},[65,4168,93],{"emptyLinePlaceholder":92},[65,4170,4171,4173,4176,4178,4181,4183,4185,4187,4189],{"class":67,"line":496},[65,4172,3173],{"class":244},[65,4174,4175],{"class":255}," imageSet",[65,4177,259],{"class":75},[65,4179,4180],{"class":345},"imageObj",[65,4182,349],{"class":75},[65,4184,4114],{"class":345},[65,4186,349],{"class":75},[65,4188,4119],{"class":345},[65,4190,4191],{"class":75},"){\n",[65,4193,4194,4196,4199,4201,4204,4206,4208],{"class":67,"line":502},[65,4195,3184],{"class":244},[65,4197,4198],{"class":248}," imgWidth",[65,4200,336],{"class":75},[65,4202,4203],{"class":248}," imageObj",[65,4205,425],{"class":75},[65,4207,3312],{"class":248},[65,4209,281],{"class":75},[65,4211,4212,4214,4217,4219,4221,4223,4225],{"class":67,"line":520},[65,4213,3184],{"class":244},[65,4215,4216],{"class":248}," imgHeight",[65,4218,336],{"class":75},[65,4220,4203],{"class":248},[65,4222,425],{"class":75},[65,4224,3340],{"class":248},[65,4226,281],{"class":75},[65,4228,4229,4232,4234,4236,4238,4240,4242,4244,4246,4248,4250,4253,4255,4258,4260,4262,4264,4266,4268,4270,4272,4274,4276],{"class":67,"line":527},[65,4230,4231],{"class":248},"    ctx",[65,4233,425],{"class":75},[65,4235,3387],{"class":255},[65,4237,259],{"class":71},[65,4239,3392],{"class":248},[65,4241,349],{"class":75},[65,4243,2988],{"class":460},[65,4245,349],{"class":75},[65,4247,2988],{"class":460},[65,4249,349],{"class":75},[65,4251,4252],{"class":248},"imgWidth",[65,4254,349],{"class":75},[65,4256,4257],{"class":248},"imgHeight",[65,4259,349],{"class":75},[65,4261,2988],{"class":460},[65,4263,349],{"class":75},[65,4265,2988],{"class":460},[65,4267,349],{"class":75},[65,4269,4114],{"class":248},[65,4271,349],{"class":75},[65,4273,4119],{"class":248},[65,4275,355],{"class":71},[65,4277,281],{"class":75},[65,4279,4280],{"class":67,"line":539},[65,4281,570],{"class":75},[65,4283,4284],{"class":67,"line":556},[65,4285,93],{"emptyLinePlaceholder":92},[65,4287,4288,4290,4293,4295,4297,4299,4301,4303,4305,4307,4310,4312,4315,4317,4320],{"class":67,"line":561},[65,4289,3173],{"class":244},[65,4291,4292],{"class":255}," waveDrawing",[65,4294,259],{"class":75},[65,4296,4133],{"class":345},[65,4298,349],{"class":75},[65,4300,4114],{"class":345},[65,4302,349],{"class":75},[65,4304,4119],{"class":345},[65,4306,349],{"class":75},[65,4308,4309],{"class":345},"deg",[65,4311,349],{"class":75},[65,4313,4314],{"class":345},"am",[65,4316,349],{"class":75},[65,4318,4319],{"class":345},"tp",[65,4321,4191],{"class":75},[65,4323,4324,4326,4329,4331,4334],{"class":67,"line":567},[65,4325,3184],{"class":244},[65,4327,4328],{"class":248}," waveStartY",[65,4330,336],{"class":75},[65,4332,4333],{"class":248}," waveStartPoint",[65,4335,281],{"class":75},[65,4337,4338,4340,4342,4345,4347,4349,4352,4354],{"class":67,"line":1343},[65,4339,4231],{"class":248},[65,4341,425],{"class":75},[65,4343,4344],{"class":248},"globalCompositeOperation",[65,4346,336],{"class":75},[65,4348,79],{"class":75},[65,4350,4351],{"class":82},"destination-out",[65,4353,313],{"class":75},[65,4355,281],{"class":75},[65,4357,4358,4360,4362,4365,4367],{"class":67,"line":1872},[65,4359,4231],{"class":248},[65,4361,425],{"class":75},[65,4363,4364],{"class":255},"beginPath",[65,4366,1208],{"class":71},[65,4368,281],{"class":75},[65,4370,4371,4373,4375,4378,4380,4382,4384,4386,4388],{"class":67,"line":1901},[65,4372,4231],{"class":248},[65,4374,425],{"class":75},[65,4376,4377],{"class":255},"moveTo",[65,4379,259],{"class":71},[65,4381,2988],{"class":460},[65,4383,349],{"class":75},[65,4385,4328],{"class":248},[65,4387,355],{"class":71},[65,4389,281],{"class":75},[65,4391,4392],{"class":67,"line":1930},[65,4393,93],{"emptyLinePlaceholder":92},[65,4395,4396,4399,4401,4403,4406,4408,4410,4413,4415,4418,4421,4423,4425,4428,4431,4434],{"class":67,"line":1959},[65,4397,4398],{"class":402},"    for",[65,4400,342],{"class":71},[65,4402,290],{"class":244},[65,4404,4405],{"class":248}," x",[65,4407,252],{"class":75},[65,4409,2988],{"class":460},[65,4411,4412],{"class":75},";",[65,4414,4405],{"class":248},[65,4416,4417],{"class":75}," \u003C=",[65,4419,4420],{"class":248}," canvasEndX",[65,4422,4412],{"class":75},[65,4424,4405],{"class":248},[65,4426,4427],{"class":75},"+=",[65,4429,4430],{"class":460}," 1",[65,4432,4433],{"class":71},") ",[65,4435,406],{"class":75},[65,4437,4438,4441,4444,4446,4449,4451,4454,4457,4459,4462,4465,4467,4469,4472,4474,4476,4478,4480,4482,4484,4487,4490,4493],{"class":67,"line":1966},[65,4439,4440],{"class":244},"        var",[65,4442,4443],{"class":248}," y",[65,4445,336],{"class":75},[65,4447,4448],{"class":75}," -",[65,4450,4314],{"class":248},[65,4452,4453],{"class":75},"*",[65,4455,4456],{"class":248},"Math",[65,4458,425],{"class":75},[65,4460,4461],{"class":255},"sin",[65,4463,4464],{"class":71},"((",[65,4466,4456],{"class":248},[65,4468,425],{"class":75},[65,4470,4471],{"class":248},"PI",[65,4473,3355],{"class":75},[65,4475,4319],{"class":248},[65,4477,355],{"class":71},[65,4479,4453],{"class":75},[65,4481,259],{"class":71},[65,4483,4309],{"class":248},[65,4485,4486],{"class":75},"+",[65,4488,4489],{"class":248},"x",[65,4491,4492],{"class":71},"))",[65,4494,281],{"class":75},[65,4496,4497,4499,4501,4504,4506,4508,4510,4512,4514,4517,4519],{"class":67,"line":1971},[65,4498,3650],{"class":248},[65,4500,425],{"class":75},[65,4502,4503],{"class":255},"lineTo",[65,4505,259],{"class":71},[65,4507,4489],{"class":248},[65,4509,349],{"class":75},[65,4511,4443],{"class":248},[65,4513,4486],{"class":75},[65,4515,4516],{"class":248},"waveStartY",[65,4518,355],{"class":71},[65,4520,281],{"class":75},[65,4522,4523],{"class":67,"line":1976},[65,4524,3449],{"class":75},[65,4526,4527],{"class":67,"line":1981},[65,4528,93],{"emptyLinePlaceholder":92},[65,4530,4531,4533,4535,4537,4539,4541,4543,4545,4547],{"class":67,"line":1986},[65,4532,4231],{"class":248},[65,4534,425],{"class":75},[65,4536,4503],{"class":255},[65,4538,259],{"class":71},[65,4540,4114],{"class":248},[65,4542,349],{"class":75},[65,4544,4119],{"class":248},[65,4546,355],{"class":71},[65,4548,281],{"class":75},[65,4550,4552,4554,4556,4558,4560,4562,4564,4566,4568],{"class":67,"line":4551},36,[65,4553,4231],{"class":248},[65,4555,425],{"class":75},[65,4557,4503],{"class":255},[65,4559,259],{"class":71},[65,4561,2988],{"class":460},[65,4563,349],{"class":75},[65,4565,4119],{"class":248},[65,4567,355],{"class":71},[65,4569,281],{"class":75},[65,4571,4573,4575,4577,4580,4582],{"class":67,"line":4572},37,[65,4574,4231],{"class":248},[65,4576,425],{"class":75},[65,4578,4579],{"class":255},"closePath",[65,4581,1208],{"class":71},[65,4583,281],{"class":75},[65,4585,4587],{"class":67,"line":4586},38,[65,4588,93],{"emptyLinePlaceholder":92},[65,4590,4592,4595,4597,4600,4602,4604,4607,4609,4611],{"class":67,"line":4591},39,[65,4593,4594],{"class":248},"    　ctx",[65,4596,425],{"class":75},[65,4598,4599],{"class":248},"fillStyle",[65,4601,336],{"class":75},[65,4603,79],{"class":75},[65,4605,4606],{"class":82},"rgba(255,255,255,1)",[65,4608,313],{"class":75},[65,4610,4412],{"class":75},[65,4612,4613],{"class":750}," \u002F\u002Fopacity 1\n",[65,4615,4617,4619,4621,4624,4626],{"class":67,"line":4616},40,[65,4618,4231],{"class":248},[65,4620,425],{"class":75},[65,4622,4623],{"class":255},"fill",[65,4625,1208],{"class":71},[65,4627,281],{"class":75},[65,4629,4631],{"class":67,"line":4630},41,[65,4632,570],{"class":75},[11,4634,4635],{},"ここでは３つの関数を作成します。",[2228,4637,4638,4641,4644],{},[2231,4639,4640],{},"initDraw()：初期の波線くりぬき画像を描画する。",[2231,4642,4643],{},"imageSet()：画像をキャンバスに描画する。またすでに画像がある場合はそれをクリアする。",[2231,4645,4646],{},"waveDrawing()：画像を波線にくり抜く。",[11,4648,4649],{},"それぞれを解説していきます。",[597,4651,4653],{"id":4652},"imageset-で画像を描画","imageSet() で画像を描画",[32,4655,4657],{"className":2016,"code":4656,"language":2018,"meta":41,"style":41},"function imageSet(imageObj,canvasEndX,canvasEndY){\n     var imgWidth = imageObj.width;\n     var imgHeight = imageObj.height;\n     ctx.drawImage(image,0,0,imgWidth,imgHeight,0,0,canvasEndX,canvasEndY);\n}\n",[39,4658,4659,4679,4696,4712,4761],{"__ignoreMap":41},[65,4660,4661,4663,4665,4667,4669,4671,4673,4675,4677],{"class":67,"line":68},[65,4662,3173],{"class":244},[65,4664,4175],{"class":255},[65,4666,259],{"class":75},[65,4668,4180],{"class":345},[65,4670,349],{"class":75},[65,4672,4114],{"class":345},[65,4674,349],{"class":75},[65,4676,4119],{"class":345},[65,4678,4191],{"class":75},[65,4680,4681,4684,4686,4688,4690,4692,4694],{"class":67,"line":89},[65,4682,4683],{"class":244},"     var",[65,4685,4198],{"class":248},[65,4687,336],{"class":75},[65,4689,4203],{"class":248},[65,4691,425],{"class":75},[65,4693,3312],{"class":248},[65,4695,281],{"class":75},[65,4697,4698,4700,4702,4704,4706,4708,4710],{"class":67,"line":96},[65,4699,4683],{"class":244},[65,4701,4216],{"class":248},[65,4703,336],{"class":75},[65,4705,4203],{"class":248},[65,4707,425],{"class":75},[65,4709,3340],{"class":248},[65,4711,281],{"class":75},[65,4713,4714,4717,4719,4721,4723,4725,4727,4729,4731,4733,4735,4737,4739,4741,4743,4745,4747,4749,4751,4753,4755,4757,4759],{"class":67,"line":105},[65,4715,4716],{"class":248},"     ctx",[65,4718,425],{"class":75},[65,4720,3387],{"class":255},[65,4722,259],{"class":71},[65,4724,3392],{"class":248},[65,4726,349],{"class":75},[65,4728,2988],{"class":460},[65,4730,349],{"class":75},[65,4732,2988],{"class":460},[65,4734,349],{"class":75},[65,4736,4252],{"class":248},[65,4738,349],{"class":75},[65,4740,4257],{"class":248},[65,4742,349],{"class":75},[65,4744,2988],{"class":460},[65,4746,349],{"class":75},[65,4748,2988],{"class":460},[65,4750,349],{"class":75},[65,4752,4114],{"class":248},[65,4754,349],{"class":75},[65,4756,4119],{"class":248},[65,4758,355],{"class":71},[65,4760,281],{"class":75},[65,4762,4763],{"class":67,"line":113},[65,4764,570],{"class":75},[11,4766,4767,4768,4770],{},"この関数は単に画像を描画するだけです。引数に画像オブジェクトとキャンバスの幅・高さ情報をとり、先ほども説明した",[39,4769,3734],{},"を用いてキャンバスに画像を描画します。",[597,4772,4774],{"id":4773},"wavedrawingで波線くりぬきをする","waveDrawing()で波線くりぬきをする",[11,4776,4777,4780],{},[39,4778,4779],{},"waveDrawing()","という関数で波線のくりぬき処理をかいていきます。",[32,4782,4784],{"className":2016,"code":4783,"language":2018,"meta":41,"style":41},"function waveDrawing(waveStartPoint,canvasEndX,canvasEndY,deg,am,tp){\n      var waveStartY = waveStartPoint;\n      ctx.globalCompositeOperation = \"destination-out\";\n      ctx.beginPath();\n      ctx.moveTo(0, waveStartY);\n\n      for (var x=0; x \u003C= canvasEndX; x+= 1) {\n           var y = -am*Math.sin((Math.PI\u002Ftp)*(deg+x));;\n           ctx.lineTo(x, y+waveStartY);\n      }\n\n      ctx.lineTo(canvasEndX,canvasEndY);\n      ctx.lineTo(0,canvasEndY);\n      ctx.closePath();\n\n      ctx.fillStyle = \"rgba(255,255,255,1)\"; \u002F\u002Fopacity 1\n      ctx.fill();\n}\n",[39,4785,4786,4818,4831,4850,4862,4882,4886,4921,4971,4996,5001,5005,5025,5045,5057,5061,5081,5093],{"__ignoreMap":41},[65,4787,4788,4790,4792,4794,4796,4798,4800,4802,4804,4806,4808,4810,4812,4814,4816],{"class":67,"line":68},[65,4789,3173],{"class":244},[65,4791,4292],{"class":255},[65,4793,259],{"class":75},[65,4795,4133],{"class":345},[65,4797,349],{"class":75},[65,4799,4114],{"class":345},[65,4801,349],{"class":75},[65,4803,4119],{"class":345},[65,4805,349],{"class":75},[65,4807,4309],{"class":345},[65,4809,349],{"class":75},[65,4811,4314],{"class":345},[65,4813,349],{"class":75},[65,4815,4319],{"class":345},[65,4817,4191],{"class":75},[65,4819,4820,4823,4825,4827,4829],{"class":67,"line":89},[65,4821,4822],{"class":244},"      var",[65,4824,4328],{"class":248},[65,4826,336],{"class":75},[65,4828,4333],{"class":248},[65,4830,281],{"class":75},[65,4832,4833,4836,4838,4840,4842,4844,4846,4848],{"class":67,"line":96},[65,4834,4835],{"class":248},"      ctx",[65,4837,425],{"class":75},[65,4839,4344],{"class":248},[65,4841,336],{"class":75},[65,4843,79],{"class":75},[65,4845,4351],{"class":82},[65,4847,313],{"class":75},[65,4849,281],{"class":75},[65,4851,4852,4854,4856,4858,4860],{"class":67,"line":105},[65,4853,4835],{"class":248},[65,4855,425],{"class":75},[65,4857,4364],{"class":255},[65,4859,1208],{"class":71},[65,4861,281],{"class":75},[65,4863,4864,4866,4868,4870,4872,4874,4876,4878,4880],{"class":67,"line":113},[65,4865,4835],{"class":248},[65,4867,425],{"class":75},[65,4869,4377],{"class":255},[65,4871,259],{"class":71},[65,4873,2988],{"class":460},[65,4875,349],{"class":75},[65,4877,4328],{"class":248},[65,4879,355],{"class":71},[65,4881,281],{"class":75},[65,4883,4884],{"class":67,"line":124},[65,4885,93],{"emptyLinePlaceholder":92},[65,4887,4888,4891,4893,4895,4897,4899,4901,4903,4905,4907,4909,4911,4913,4915,4917,4919],{"class":67,"line":135},[65,4889,4890],{"class":402},"      for",[65,4892,342],{"class":71},[65,4894,290],{"class":244},[65,4896,4405],{"class":248},[65,4898,252],{"class":75},[65,4900,2988],{"class":460},[65,4902,4412],{"class":75},[65,4904,4405],{"class":248},[65,4906,4417],{"class":75},[65,4908,4420],{"class":248},[65,4910,4412],{"class":75},[65,4912,4405],{"class":248},[65,4914,4427],{"class":75},[65,4916,4430],{"class":460},[65,4918,4433],{"class":71},[65,4920,406],{"class":75},[65,4922,4923,4926,4928,4930,4932,4934,4936,4938,4940,4942,4944,4946,4948,4950,4952,4954,4956,4958,4960,4962,4964,4966,4968],{"class":67,"line":143},[65,4924,4925],{"class":244},"           var",[65,4927,4443],{"class":248},[65,4929,336],{"class":75},[65,4931,4448],{"class":75},[65,4933,4314],{"class":248},[65,4935,4453],{"class":75},[65,4937,4456],{"class":248},[65,4939,425],{"class":75},[65,4941,4461],{"class":255},[65,4943,4464],{"class":71},[65,4945,4456],{"class":248},[65,4947,425],{"class":75},[65,4949,4471],{"class":248},[65,4951,3355],{"class":75},[65,4953,4319],{"class":248},[65,4955,355],{"class":71},[65,4957,4453],{"class":75},[65,4959,259],{"class":71},[65,4961,4309],{"class":248},[65,4963,4486],{"class":75},[65,4965,4489],{"class":248},[65,4967,4492],{"class":71},[65,4969,4970],{"class":75},";;\n",[65,4972,4973,4976,4978,4980,4982,4984,4986,4988,4990,4992,4994],{"class":67,"line":152},[65,4974,4975],{"class":248},"           ctx",[65,4977,425],{"class":75},[65,4979,4503],{"class":255},[65,4981,259],{"class":71},[65,4983,4489],{"class":248},[65,4985,349],{"class":75},[65,4987,4443],{"class":248},[65,4989,4486],{"class":75},[65,4991,4516],{"class":248},[65,4993,355],{"class":71},[65,4995,281],{"class":75},[65,4997,4998],{"class":67,"line":163},[65,4999,5000],{"class":75},"      }\n",[65,5002,5003],{"class":67,"line":171},[65,5004,93],{"emptyLinePlaceholder":92},[65,5006,5007,5009,5011,5013,5015,5017,5019,5021,5023],{"class":67,"line":179},[65,5008,4835],{"class":248},[65,5010,425],{"class":75},[65,5012,4503],{"class":255},[65,5014,259],{"class":71},[65,5016,4114],{"class":248},[65,5018,349],{"class":75},[65,5020,4119],{"class":248},[65,5022,355],{"class":71},[65,5024,281],{"class":75},[65,5026,5027,5029,5031,5033,5035,5037,5039,5041,5043],{"class":67,"line":187},[65,5028,4835],{"class":248},[65,5030,425],{"class":75},[65,5032,4503],{"class":255},[65,5034,259],{"class":71},[65,5036,2988],{"class":460},[65,5038,349],{"class":75},[65,5040,4119],{"class":248},[65,5042,355],{"class":71},[65,5044,281],{"class":75},[65,5046,5047,5049,5051,5053,5055],{"class":67,"line":195},[65,5048,4835],{"class":248},[65,5050,425],{"class":75},[65,5052,4579],{"class":255},[65,5054,1208],{"class":71},[65,5056,281],{"class":75},[65,5058,5059],{"class":67,"line":203},[65,5060,93],{"emptyLinePlaceholder":92},[65,5062,5063,5065,5067,5069,5071,5073,5075,5077,5079],{"class":67,"line":211},[65,5064,4835],{"class":248},[65,5066,425],{"class":75},[65,5068,4599],{"class":248},[65,5070,336],{"class":75},[65,5072,79],{"class":75},[65,5074,4606],{"class":82},[65,5076,313],{"class":75},[65,5078,4412],{"class":75},[65,5080,4613],{"class":750},[65,5082,5083,5085,5087,5089,5091],{"class":67,"line":466},[65,5084,4835],{"class":248},[65,5086,425],{"class":75},[65,5088,4623],{"class":255},[65,5090,1208],{"class":71},[65,5092,281],{"class":75},[65,5094,5095],{"class":67,"line":496},[65,5096,570],{"class":75},[11,5098,5099],{},"各パラメーターは",[2228,5101,5102,5105,5108,5111,5114,5117],{},[2231,5103,5104],{},"waveStartPoint：波を書き始めるY軸の開始位置",[2231,5106,5107],{},"canvasEndX：canvasの右端のX座標（最大のcanvasX座標）",[2231,5109,5110],{},"canvasEndY：canvasの下端のY座標（最大のcanvasXY座標）",[2231,5112,5113],{},"deg：角度の初期値",[2231,5115,5116],{},"am：振幅（波の最大の高さを変化させる）",[2231,5118,5119],{},"tp：周期（１波の幅を変化させる）",[11,5121,5122],{},"最後の３つは高校の三角関数を思い出してください。それほど難しく考えず、amを大きくすれば波が大きくなり、tpの場合は大きいほどなだらかな波になります。",[11,5124,5125],{},"またctxは上部で定義したcanvasインスタンスです。今回はグローバルにしてます。",[2326,5127,5129],{"id":5128},"描画位置を定義し重ね合わせの設定をする","描画位置を定義し、重ね合わせの設定をする",[32,5131,5133],{"className":2016,"code":5132,"language":2018,"meta":41,"style":41},"var waveStartY = waveStartPoint;\nctx.globalCompositeOperation = \"destination-out\";\nctx.beginPath();\nctx.moveTo(0, waveStartY);\n",[39,5134,5135,5148,5167,5179],{"__ignoreMap":41},[65,5136,5137,5139,5142,5144,5146],{"class":67,"line":68},[65,5138,290],{"class":244},[65,5140,5141],{"class":248}," waveStartY ",[65,5143,252],{"class":75},[65,5145,4333],{"class":248},[65,5147,281],{"class":75},[65,5149,5150,5152,5154,5157,5159,5161,5163,5165],{"class":67,"line":89},[65,5151,3862],{"class":248},[65,5153,425],{"class":75},[65,5155,5156],{"class":248},"globalCompositeOperation ",[65,5158,252],{"class":75},[65,5160,79],{"class":75},[65,5162,4351],{"class":82},[65,5164,313],{"class":75},[65,5166,281],{"class":75},[65,5168,5169,5171,5173,5175,5177],{"class":67,"line":96},[65,5170,3862],{"class":248},[65,5172,425],{"class":75},[65,5174,4364],{"class":255},[65,5176,1208],{"class":248},[65,5178,281],{"class":75},[65,5180,5181,5183,5185,5187,5189,5191,5193,5196],{"class":67,"line":105},[65,5182,3862],{"class":248},[65,5184,425],{"class":75},[65,5186,4377],{"class":255},[65,5188,259],{"class":248},[65,5190,2988],{"class":460},[65,5192,349],{"class":75},[65,5194,5195],{"class":248}," waveStartY)",[65,5197,281],{"class":75},[11,5199,5200,5201,5204,5205],{},"画像を波線に透過させる場合にこの設定 ",[39,5202,5203],{},"ctx.globalCompositeOperation = \"destination-out\"; ","が重要です。",[21,5206,5209],{"href":5207,"rel":5208},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FAPI\u002FCanvasRenderingContext2D\u002FglobalCompositeOperation",[25],"MDNの解説",[11,5211,5212,5213,5215],{},"この",[39,5214,4344],{},"はcanvasにおける図形どうしが重ね合わさった際にどう描画するのかを定義します。冒頭で出したこの図を見てみてください。",[1503,5217],{":src":2840,":width":1506},[11,5219,5220],{},"透明のくりぬきは画像の上に、赤線で範囲を指定してその中を透明色に塗りつぶすということをしています。その時に「すでに描画された画像」と「透明色に塗り潰された図形」が重ね合わさっています。",[11,5222,5223],{},"その時にを設定していると、後で描画した図形と重なり合わない部分だけが残る様に描画されます。つまり上図の５の様に一部分だけ透明になります。",[2326,5225,5226],{"id":5226},"くりぬき範囲を指定する",[32,5228,5230],{"className":2016,"code":5229,"language":2018,"meta":41,"style":41}," ctx.beginPath();\n ctx.moveTo(0, waveStartY);\n for (var x=0; x \u003C= canvasEndX; x+= 1) {\n     var y = -am*Math.sin((Math.PI\u002Ftp)*(deg+x));;\n     ctx.lineTo(x, y+waveStartY);\n }\n\n ctx.lineTo(canvasEndX,canvasEndY);\n ctx.lineTo(0,canvasEndY);\n ctx.closePath();\n",[39,5231,5232,5244,5262,5299,5347,5371,5375,5379,5397,5415],{"__ignoreMap":41},[65,5233,5234,5236,5238,5240,5242],{"class":67,"line":68},[65,5235,3216],{"class":248},[65,5237,425],{"class":75},[65,5239,4364],{"class":255},[65,5241,1208],{"class":248},[65,5243,281],{"class":75},[65,5245,5246,5248,5250,5252,5254,5256,5258,5260],{"class":67,"line":89},[65,5247,3216],{"class":248},[65,5249,425],{"class":75},[65,5251,4377],{"class":255},[65,5253,259],{"class":248},[65,5255,2988],{"class":460},[65,5257,349],{"class":75},[65,5259,5195],{"class":248},[65,5261,281],{"class":75},[65,5263,5264,5267,5269,5271,5273,5275,5277,5279,5282,5285,5287,5289,5291,5293,5295,5297],{"class":67,"line":96},[65,5265,5266],{"class":402}," for",[65,5268,342],{"class":248},[65,5270,290],{"class":244},[65,5272,4405],{"class":248},[65,5274,252],{"class":75},[65,5276,2988],{"class":460},[65,5278,4412],{"class":75},[65,5280,5281],{"class":248}," x ",[65,5283,5284],{"class":75},"\u003C=",[65,5286,4420],{"class":248},[65,5288,4412],{"class":75},[65,5290,4405],{"class":248},[65,5292,4427],{"class":75},[65,5294,4430],{"class":460},[65,5296,4433],{"class":248},[65,5298,406],{"class":75},[65,5300,5301,5303,5305,5307,5309,5311,5313,5315,5317,5319,5321,5323,5325,5327,5329,5331,5333,5335,5337,5339,5341,5343,5345],{"class":67,"line":105},[65,5302,4683],{"class":244},[65,5304,4443],{"class":248},[65,5306,336],{"class":75},[65,5308,4448],{"class":75},[65,5310,4314],{"class":248},[65,5312,4453],{"class":75},[65,5314,4456],{"class":248},[65,5316,425],{"class":75},[65,5318,4461],{"class":255},[65,5320,4464],{"class":71},[65,5322,4456],{"class":248},[65,5324,425],{"class":75},[65,5326,4471],{"class":248},[65,5328,3355],{"class":75},[65,5330,4319],{"class":248},[65,5332,355],{"class":71},[65,5334,4453],{"class":75},[65,5336,259],{"class":71},[65,5338,4309],{"class":248},[65,5340,4486],{"class":75},[65,5342,4489],{"class":248},[65,5344,4492],{"class":71},[65,5346,4970],{"class":75},[65,5348,5349,5351,5353,5355,5357,5359,5361,5363,5365,5367,5369],{"class":67,"line":113},[65,5350,4716],{"class":248},[65,5352,425],{"class":75},[65,5354,4503],{"class":255},[65,5356,259],{"class":71},[65,5358,4489],{"class":248},[65,5360,349],{"class":75},[65,5362,4443],{"class":248},[65,5364,4486],{"class":75},[65,5366,4516],{"class":248},[65,5368,355],{"class":71},[65,5370,281],{"class":75},[65,5372,5373],{"class":67,"line":124},[65,5374,1847],{"class":75},[65,5376,5377],{"class":67,"line":135},[65,5378,93],{"emptyLinePlaceholder":92},[65,5380,5381,5383,5385,5387,5390,5392,5395],{"class":67,"line":143},[65,5382,3216],{"class":248},[65,5384,425],{"class":75},[65,5386,4503],{"class":255},[65,5388,5389],{"class":248},"(canvasEndX",[65,5391,349],{"class":75},[65,5393,5394],{"class":248},"canvasEndY)",[65,5396,281],{"class":75},[65,5398,5399,5401,5403,5405,5407,5409,5411,5413],{"class":67,"line":152},[65,5400,3216],{"class":248},[65,5402,425],{"class":75},[65,5404,4503],{"class":255},[65,5406,259],{"class":248},[65,5408,2988],{"class":460},[65,5410,349],{"class":75},[65,5412,5394],{"class":248},[65,5414,281],{"class":75},[65,5416,5417,5419,5421,5423,5425],{"class":67,"line":163},[65,5418,3216],{"class":248},[65,5420,425],{"class":75},[65,5422,4579],{"class":255},[65,5424,1208],{"class":248},[65,5426,281],{"class":75},[11,5428,5429],{},"次にくりぬきの範囲を指定します。上図でいうと１〜４を指します。フォトショップやイラストレーターを使っている人なら「パスで選択範囲を指定」という意味がわかると思います。それをここでjsを用いて行っています。",[11,5431,5432],{},"念のために解説すると、パスというのは図形を構成する点（座標）みたいなものです。そして図形はその点を結ぶことで描画できます。四角形であれば点（頂点）は４つあって、それを一筆書きすると四角ができますよね。その一筆書きの順路と位置をこのコードで定義しています。",[2446,5434,5435,5438,5441,5444],{},[2231,5436,5437],{},"ctx.beginPath()でパスの指定を開始します。",[2231,5439,5440],{},"ctx.moveTo(X,Y)で指定した座標にパスを移動させます。",[2231,5442,5443],{},"ctx.lineTo(nextX,nextY)で次の座標を指定しパスを移動させつつ線をひきます。",[2231,5445,5446],{},"ctx.closePath()でパスの指定を終了します。",[11,5448,5449],{},"今回はこのパスの指定を",[2446,5451,5452,5455,5458,5461],{},[2231,5453,5454],{},"画像の左端（X=０）、指定した波の開始地点（waveStartY）より（0, waveStartY）からパスを開始。",[2231,5456,5457],{},"画像の右端（X＝canvasEndX）までfor文を用いて、さらに三角関数の式にx座標を入れて、波線を描く様にパスを指定していく。",[2231,5459,5460],{},"画像の右端までついたら、画像の右下端、左下端を通って、開始地点に戻る。",[2231,5462,5463],{},"パスを閉じる。",[11,5465,5466],{},"この様にしています。",[2326,5468,5469],{"id":5469},"選択範囲を透明色で塗りつぶす",[11,5471,5472],{},"上記の方法で選択範囲を指定すれば、あとは塗りつぶすだけです。",[32,5474,5476],{"className":2016,"code":5475,"language":2018,"meta":41,"style":41},"ctx.fillStyle = \"rgba(255,255,255,1)\"; \u002F\u002Fopacity 1\nctx.fill();\n",[39,5477,5478,5499],{"__ignoreMap":41},[65,5479,5480,5482,5484,5487,5489,5491,5493,5495,5497],{"class":67,"line":68},[65,5481,3862],{"class":248},[65,5483,425],{"class":75},[65,5485,5486],{"class":248},"fillStyle ",[65,5488,252],{"class":75},[65,5490,79],{"class":75},[65,5492,4606],{"class":82},[65,5494,313],{"class":75},[65,5496,4412],{"class":75},[65,5498,4613],{"class":750},[65,5500,5501,5503,5505,5507,5509],{"class":67,"line":89},[65,5502,3862],{"class":248},[65,5504,425],{"class":75},[65,5506,4623],{"class":255},[65,5508,1208],{"class":248},[65,5510,281],{"class":75},[11,5512,5513,5515,5516,5519],{},[39,5514,4599],{},"で塗り潰しの色を設定できます。ここは実際、",[39,5517,5518],{},"globalCompositeOperation = \"destination-out\";","を設定していれば何色でも大丈夫です。ですが念のため透明色を設定。",[11,5521,3518,5522,5525,5526,5529],{},[39,5523,5524],{},"fill()","で指定したスタイル、パスの範囲で塗り潰しを行います。g",[39,5527,5528],{},"lobalCompositeOperation = \"destination-out\";","が設定されているので塗り潰された部分と画像の重なり合う部分以外が残り、重なり部分は透明になります。",[11,5531,5532],{},"ここまで来れば以下の様に波線にくり抜かれた画像が得られます。",[1503,5534],{":src":2794,":width":1506},[49,5536,5537],{"id":5537},"ループでアニメーションを実装",[11,5539,5540,5541,5544,5545,5547],{},"定義した",[39,5542,5543],{},"imageSet()","と",[39,5546,4779],{},"を用いて以下のループを設定します。",[32,5549,5551],{"className":2016,"code":5550,"language":2018,"meta":41,"style":41},"function loop(){\n      setInterval(function(){\n      imageSet(image,canvasEndX,canvasEndY);\n      waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);\n      degree += 12; \u002F\u002F12はなんとなく\n    },30)\n}\n",[39,5552,5553,5562,5573,5594,5627,5643,5653],{"__ignoreMap":41},[65,5554,5555,5557,5560],{"class":67,"line":68},[65,5556,3173],{"class":244},[65,5558,5559],{"class":255}," loop",[65,5561,3179],{"class":75},[65,5563,5564,5567,5569,5571],{"class":67,"line":89},[65,5565,5566],{"class":255},"      setInterval",[65,5568,259],{"class":71},[65,5570,3173],{"class":244},[65,5572,3179],{"class":75},[65,5574,5575,5578,5580,5582,5584,5586,5588,5590,5592],{"class":67,"line":96},[65,5576,5577],{"class":255},"      imageSet",[65,5579,259],{"class":71},[65,5581,3392],{"class":248},[65,5583,349],{"class":75},[65,5585,4114],{"class":248},[65,5587,349],{"class":75},[65,5589,4119],{"class":248},[65,5591,355],{"class":71},[65,5593,281],{"class":75},[65,5595,5596,5599,5601,5603,5605,5607,5609,5611,5613,5615,5617,5619,5621,5623,5625],{"class":67,"line":105},[65,5597,5598],{"class":255},"      waveDrawing",[65,5600,259],{"class":71},[65,5602,4133],{"class":248},[65,5604,349],{"class":75},[65,5606,4114],{"class":248},[65,5608,349],{"class":75},[65,5610,4119],{"class":248},[65,5612,349],{"class":75},[65,5614,4146],{"class":248},[65,5616,349],{"class":75},[65,5618,4151],{"class":248},[65,5620,349],{"class":75},[65,5622,4156],{"class":248},[65,5624,355],{"class":71},[65,5626,281],{"class":75},[65,5628,5629,5632,5635,5638,5640],{"class":67,"line":113},[65,5630,5631],{"class":248},"      degree",[65,5633,5634],{"class":75}," +=",[65,5636,5637],{"class":460}," 12",[65,5639,4412],{"class":75},[65,5641,5642],{"class":750}," \u002F\u002F12はなんとなく\n",[65,5644,5645,5648,5651],{"class":67,"line":124},[65,5646,5647],{"class":75},"    },",[65,5649,5650],{"class":460},"30",[65,5652,270],{"class":71},[65,5654,5655],{"class":67,"line":135},[65,5656,570],{"class":75},[11,5658,5659,5660,5663,5664,5666],{},"ここで一番大切なのは",[39,5661,5662],{},"deggre +=4","の様に",[39,5665,4779],{},"で用いる初期角度を足していくことです。こうすることで波がウネウネします。degreeの加算が多いほど波が早くなります。50以上にすると荒波になります笑",[11,5668,5669,5670,5673,5674,5676],{},"そしてこの",[39,5671,5672],{},"loop()","の関数を",[39,5675,3730],{},"で呼び出して発火させます。",[32,5678,5680],{"className":2016,"code":5679,"language":2018,"meta":41,"style":41},"image.onload = function(){\n    initDraw();\n    loop();\n}\n",[39,5681,5682,5696,5704,5713],{"__ignoreMap":41},[65,5683,5684,5686,5688,5690,5692,5694],{"class":67,"line":68},[65,5685,3392],{"class":248},[65,5687,425],{"class":75},[65,5689,3370],{"class":255},[65,5691,336],{"class":75},[65,5693,3375],{"class":244},[65,5695,3179],{"class":75},[65,5697,5698,5700,5702],{"class":67,"line":89},[65,5699,3974],{"class":255},[65,5701,1208],{"class":71},[65,5703,281],{"class":75},[65,5705,5706,5709,5711],{"class":67,"line":96},[65,5707,5708],{"class":255},"    loop",[65,5710,1208],{"class":71},[65,5712,281],{"class":75},[65,5714,5715],{"class":67,"line":105},[65,5716,570],{"class":75},[49,5718,5719],{"id":5719},"コード全体",[11,5721,5722],{},"上記をまとめたコードがこちらです。",[32,5724,5726],{"className":2016,"code":5725,"language":2018,"meta":41,"style":41},"window.onload = init();\nfunction init(){\n    initAnimation();\n\n    function initAnimation(){\n        var canvas = document.getElementById('canvas');\n        var ctx = canvas.getContext('2d');\n\n        var imagePath = ('.\u002Fsample.jpg');\n        var image = new Image();\n        image.src = imagePath;\n\n        \u002F\u002Fset canvas width and height\n        canvas.width = Number(window.innerWidth);\n        canvas.height = Number(canvas.width\u002F2);\n        image.onload = function(){\n                initDraw();\n                loop();\n            }\n            \n        var canvasEndX = canvas.width;\n        var canvasEndY = canvas.height;\n        var waveStartPoint = canvasEndY-150;\n\n        var amplitude = 30;\n        var period = 600;\n        var degree = 0;\n\n        function initDraw(){\n            imageSet(image,canvasEndX,canvasEndY);\n            waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);\n        }\n\n        function loop(){\n            setInterval(function(){\n                imageSet(image,canvasEndX,canvasEndY);\n                waveDrawing(waveStartPoint,canvasEndX,canvasEndY,degree,amplitude,period);\n                degree += 12;\n            },30)\n        }\n\n        function imageSet(imageObj,canvasEndX,canvasEndY){\n            var imgWidth = imageObj.width;\n            var imgHeight = imageObj.height;\n\n            ctx.globalCompositeOperation = \"destination-over\";\n            ctx.drawImage(image,0,0,imgWidth,imgHeight,0,0,canvasEndX,canvasEndY);\n        }\n\n        function waveDrawing(waveStartPoint,canvasEndX,canvasEndY,deg,am,tp){\n            var waveStartY = waveStartPoint;\n            ctx.globalCompositeOperation = \"destination-out\";\n            ctx.beginPath();\n            ctx.moveTo(0, waveStartY);\n\n            for (var x=0; x \u003C= canvasEndX; x+= 1) {\n                var y = -am*Math.sin((Math.PI\u002Ftp)*(deg+x));\n                ctx.lineTo(x, y+waveStartY);\n            }\n\n            ctx.lineTo(canvasEndX,canvasEndY);\n            ctx.lineTo(0,canvasEndY);\n            ctx.closePath();\n\n            ctx.fillStyle = \"rgba(255,255,255,1)\"; \u002F\u002Fopacity 1\n            ctx.fill();\n        }\n\n    }\n}\n",[39,5727,5728,5746,5754,5763,5767,5776,5802,5828,5832,5852,5868,5883,5887,5892,5917,5945,5959,5968,5977,5981,5986,6002,6018,6034,6038,6051,6065,6078,6082,6091,6112,6145,6149,6153,6161,6172,6193,6226,6237,6246,6250,6254,6275,6293,6310,6315,6336,6385,6390,6395,6428,6441,6460,6473,6494,6499,6535,6585,6611,6616,6621,6642,6663,6676,6681,6702,6715,6720,6725,6730],{"__ignoreMap":41},[65,5729,5730,5732,5734,5737,5739,5742,5744],{"class":67,"line":68},[65,5731,3322],{"class":248},[65,5733,425],{"class":75},[65,5735,5736],{"class":248},"onload ",[65,5738,252],{"class":75},[65,5740,5741],{"class":255}," init",[65,5743,1208],{"class":248},[65,5745,281],{"class":75},[65,5747,5748,5750,5752],{"class":67,"line":89},[65,5749,3173],{"class":244},[65,5751,5741],{"class":255},[65,5753,3179],{"class":75},[65,5755,5756,5759,5761],{"class":67,"line":96},[65,5757,5758],{"class":255},"    initAnimation",[65,5760,1208],{"class":71},[65,5762,281],{"class":75},[65,5764,5765],{"class":67,"line":105},[65,5766,93],{"emptyLinePlaceholder":92},[65,5768,5769,5772,5774],{"class":67,"line":113},[65,5770,5771],{"class":244},"    function",[65,5773,3176],{"class":255},[65,5775,3179],{"class":75},[65,5777,5778,5780,5782,5784,5786,5788,5790,5792,5794,5796,5798,5800],{"class":67,"line":124},[65,5779,4440],{"class":244},[65,5781,3187],{"class":248},[65,5783,336],{"class":75},[65,5785,3192],{"class":248},[65,5787,425],{"class":75},[65,5789,3197],{"class":255},[65,5791,259],{"class":71},[65,5793,262],{"class":75},[65,5795,3088],{"class":82},[65,5797,262],{"class":75},[65,5799,355],{"class":71},[65,5801,281],{"class":75},[65,5803,5804,5806,5808,5810,5812,5814,5816,5818,5820,5822,5824,5826],{"class":67,"line":135},[65,5805,4440],{"class":244},[65,5807,3216],{"class":248},[65,5809,336],{"class":75},[65,5811,3187],{"class":248},[65,5813,425],{"class":75},[65,5815,3225],{"class":255},[65,5817,259],{"class":71},[65,5819,262],{"class":75},[65,5821,3232],{"class":82},[65,5823,262],{"class":75},[65,5825,355],{"class":71},[65,5827,281],{"class":75},[65,5829,5830],{"class":67,"line":143},[65,5831,93],{"emptyLinePlaceholder":92},[65,5833,5834,5836,5838,5840,5842,5844,5846,5848,5850],{"class":67,"line":152},[65,5835,4440],{"class":244},[65,5837,3249],{"class":248},[65,5839,336],{"class":75},[65,5841,342],{"class":71},[65,5843,262],{"class":75},[65,5845,3258],{"class":82},[65,5847,262],{"class":75},[65,5849,355],{"class":71},[65,5851,281],{"class":75},[65,5853,5854,5856,5858,5860,5862,5864,5866],{"class":67,"line":163},[65,5855,4440],{"class":244},[65,5857,3271],{"class":248},[65,5859,336],{"class":75},[65,5861,3276],{"class":75},[65,5863,3279],{"class":255},[65,5865,1208],{"class":71},[65,5867,281],{"class":75},[65,5869,5870,5873,5875,5877,5879,5881],{"class":67,"line":171},[65,5871,5872],{"class":248},"        image",[65,5874,425],{"class":75},[65,5876,3292],{"class":248},[65,5878,336],{"class":75},[65,5880,3249],{"class":248},[65,5882,281],{"class":75},[65,5884,5885],{"class":67,"line":179},[65,5886,93],{"emptyLinePlaceholder":92},[65,5888,5889],{"class":67,"line":187},[65,5890,5891],{"class":750},"        \u002F\u002Fset canvas width and height\n",[65,5893,5894,5897,5899,5901,5903,5905,5907,5909,5911,5913,5915],{"class":67,"line":195},[65,5895,5896],{"class":248},"        canvas",[65,5898,425],{"class":75},[65,5900,3312],{"class":248},[65,5902,336],{"class":75},[65,5904,3317],{"class":255},[65,5906,259],{"class":71},[65,5908,3322],{"class":248},[65,5910,425],{"class":75},[65,5912,3327],{"class":248},[65,5914,355],{"class":71},[65,5916,281],{"class":75},[65,5918,5919,5921,5923,5925,5927,5929,5931,5933,5935,5937,5939,5941,5943],{"class":67,"line":203},[65,5920,5896],{"class":248},[65,5922,425],{"class":75},[65,5924,3340],{"class":248},[65,5926,336],{"class":75},[65,5928,3317],{"class":255},[65,5930,259],{"class":71},[65,5932,3088],{"class":248},[65,5934,425],{"class":75},[65,5936,3312],{"class":248},[65,5938,3355],{"class":75},[65,5940,860],{"class":460},[65,5942,355],{"class":71},[65,5944,281],{"class":75},[65,5946,5947,5949,5951,5953,5955,5957],{"class":67,"line":211},[65,5948,5872],{"class":248},[65,5950,425],{"class":75},[65,5952,3370],{"class":255},[65,5954,336],{"class":75},[65,5956,3375],{"class":244},[65,5958,3179],{"class":75},[65,5960,5961,5964,5966],{"class":67,"line":466},[65,5962,5963],{"class":255},"                initDraw",[65,5965,1208],{"class":71},[65,5967,281],{"class":75},[65,5969,5970,5973,5975],{"class":67,"line":496},[65,5971,5972],{"class":255},"                loop",[65,5974,1208],{"class":71},[65,5976,281],{"class":75},[65,5978,5979],{"class":67,"line":502},[65,5980,3006],{"class":75},[65,5982,5983],{"class":67,"line":520},[65,5984,5985],{"class":71},"            \n",[65,5987,5988,5990,5992,5994,5996,5998,6000],{"class":67,"line":527},[65,5989,4440],{"class":244},[65,5991,4420],{"class":248},[65,5993,336],{"class":75},[65,5995,3187],{"class":248},[65,5997,425],{"class":75},[65,5999,3312],{"class":248},[65,6001,281],{"class":75},[65,6003,6004,6006,6008,6010,6012,6014,6016],{"class":67,"line":539},[65,6005,4440],{"class":244},[65,6007,4033],{"class":248},[65,6009,336],{"class":75},[65,6011,3187],{"class":248},[65,6013,425],{"class":75},[65,6015,3340],{"class":248},[65,6017,281],{"class":75},[65,6019,6020,6022,6024,6026,6028,6030,6032],{"class":67,"line":556},[65,6021,4440],{"class":244},[65,6023,4333],{"class":248},[65,6025,336],{"class":75},[65,6027,4033],{"class":248},[65,6029,4036],{"class":75},[65,6031,4039],{"class":460},[65,6033,281],{"class":75},[65,6035,6036],{"class":67,"line":561},[65,6037,93],{"emptyLinePlaceholder":92},[65,6039,6040,6042,6045,6047,6049],{"class":67,"line":567},[65,6041,4440],{"class":244},[65,6043,6044],{"class":248}," amplitude",[65,6046,336],{"class":75},[65,6048,4057],{"class":460},[65,6050,281],{"class":75},[65,6052,6053,6055,6058,6060,6063],{"class":67,"line":1343},[65,6054,4440],{"class":244},[65,6056,6057],{"class":248}," period",[65,6059,336],{"class":75},[65,6061,6062],{"class":460}," 600",[65,6064,281],{"class":75},[65,6066,6067,6069,6072,6074,6076],{"class":67,"line":1872},[65,6068,4440],{"class":244},[65,6070,6071],{"class":248}," degree",[65,6073,336],{"class":75},[65,6075,4085],{"class":460},[65,6077,281],{"class":75},[65,6079,6080],{"class":67,"line":1901},[65,6081,93],{"emptyLinePlaceholder":92},[65,6083,6084,6087,6089],{"class":67,"line":1930},[65,6085,6086],{"class":244},"        function",[65,6088,4098],{"class":255},[65,6090,3179],{"class":75},[65,6092,6093,6096,6098,6100,6102,6104,6106,6108,6110],{"class":67,"line":1959},[65,6094,6095],{"class":255},"            imageSet",[65,6097,259],{"class":71},[65,6099,3392],{"class":248},[65,6101,349],{"class":75},[65,6103,4114],{"class":248},[65,6105,349],{"class":75},[65,6107,4119],{"class":248},[65,6109,355],{"class":71},[65,6111,281],{"class":75},[65,6113,6114,6117,6119,6121,6123,6125,6127,6129,6131,6133,6135,6137,6139,6141,6143],{"class":67,"line":1966},[65,6115,6116],{"class":255},"            waveDrawing",[65,6118,259],{"class":71},[65,6120,4133],{"class":248},[65,6122,349],{"class":75},[65,6124,4114],{"class":248},[65,6126,349],{"class":75},[65,6128,4119],{"class":248},[65,6130,349],{"class":75},[65,6132,4146],{"class":248},[65,6134,349],{"class":75},[65,6136,4151],{"class":248},[65,6138,349],{"class":75},[65,6140,4156],{"class":248},[65,6142,355],{"class":71},[65,6144,281],{"class":75},[65,6146,6147],{"class":67,"line":1971},[65,6148,564],{"class":75},[65,6150,6151],{"class":67,"line":1976},[65,6152,93],{"emptyLinePlaceholder":92},[65,6154,6155,6157,6159],{"class":67,"line":1981},[65,6156,6086],{"class":244},[65,6158,5559],{"class":255},[65,6160,3179],{"class":75},[65,6162,6163,6166,6168,6170],{"class":67,"line":1986},[65,6164,6165],{"class":255},"            setInterval",[65,6167,259],{"class":71},[65,6169,3173],{"class":244},[65,6171,3179],{"class":75},[65,6173,6174,6177,6179,6181,6183,6185,6187,6189,6191],{"class":67,"line":4551},[65,6175,6176],{"class":255},"                imageSet",[65,6178,259],{"class":71},[65,6180,3392],{"class":248},[65,6182,349],{"class":75},[65,6184,4114],{"class":248},[65,6186,349],{"class":75},[65,6188,4119],{"class":248},[65,6190,355],{"class":71},[65,6192,281],{"class":75},[65,6194,6195,6198,6200,6202,6204,6206,6208,6210,6212,6214,6216,6218,6220,6222,6224],{"class":67,"line":4572},[65,6196,6197],{"class":255},"                waveDrawing",[65,6199,259],{"class":71},[65,6201,4133],{"class":248},[65,6203,349],{"class":75},[65,6205,4114],{"class":248},[65,6207,349],{"class":75},[65,6209,4119],{"class":248},[65,6211,349],{"class":75},[65,6213,4146],{"class":248},[65,6215,349],{"class":75},[65,6217,4151],{"class":248},[65,6219,349],{"class":75},[65,6221,4156],{"class":248},[65,6223,355],{"class":71},[65,6225,281],{"class":75},[65,6227,6228,6231,6233,6235],{"class":67,"line":4586},[65,6229,6230],{"class":248},"                degree",[65,6232,5634],{"class":75},[65,6234,5637],{"class":460},[65,6236,281],{"class":75},[65,6238,6239,6242,6244],{"class":67,"line":4591},[65,6240,6241],{"class":75},"            },",[65,6243,5650],{"class":460},[65,6245,270],{"class":71},[65,6247,6248],{"class":67,"line":4616},[65,6249,564],{"class":75},[65,6251,6252],{"class":67,"line":4630},[65,6253,93],{"emptyLinePlaceholder":92},[65,6255,6257,6259,6261,6263,6265,6267,6269,6271,6273],{"class":67,"line":6256},42,[65,6258,6086],{"class":244},[65,6260,4175],{"class":255},[65,6262,259],{"class":75},[65,6264,4180],{"class":345},[65,6266,349],{"class":75},[65,6268,4114],{"class":345},[65,6270,349],{"class":75},[65,6272,4119],{"class":345},[65,6274,4191],{"class":75},[65,6276,6278,6281,6283,6285,6287,6289,6291],{"class":67,"line":6277},43,[65,6279,6280],{"class":244},"            var",[65,6282,4198],{"class":248},[65,6284,336],{"class":75},[65,6286,4203],{"class":248},[65,6288,425],{"class":75},[65,6290,3312],{"class":248},[65,6292,281],{"class":75},[65,6294,6296,6298,6300,6302,6304,6306,6308],{"class":67,"line":6295},44,[65,6297,6280],{"class":244},[65,6299,4216],{"class":248},[65,6301,336],{"class":75},[65,6303,4203],{"class":248},[65,6305,425],{"class":75},[65,6307,3340],{"class":248},[65,6309,281],{"class":75},[65,6311,6313],{"class":67,"line":6312},45,[65,6314,93],{"emptyLinePlaceholder":92},[65,6316,6318,6321,6323,6325,6327,6329,6332,6334],{"class":67,"line":6317},46,[65,6319,6320],{"class":248},"            ctx",[65,6322,425],{"class":75},[65,6324,4344],{"class":248},[65,6326,336],{"class":75},[65,6328,79],{"class":75},[65,6330,6331],{"class":82},"destination-over",[65,6333,313],{"class":75},[65,6335,281],{"class":75},[65,6337,6339,6341,6343,6345,6347,6349,6351,6353,6355,6357,6359,6361,6363,6365,6367,6369,6371,6373,6375,6377,6379,6381,6383],{"class":67,"line":6338},47,[65,6340,6320],{"class":248},[65,6342,425],{"class":75},[65,6344,3387],{"class":255},[65,6346,259],{"class":71},[65,6348,3392],{"class":248},[65,6350,349],{"class":75},[65,6352,2988],{"class":460},[65,6354,349],{"class":75},[65,6356,2988],{"class":460},[65,6358,349],{"class":75},[65,6360,4252],{"class":248},[65,6362,349],{"class":75},[65,6364,4257],{"class":248},[65,6366,349],{"class":75},[65,6368,2988],{"class":460},[65,6370,349],{"class":75},[65,6372,2988],{"class":460},[65,6374,349],{"class":75},[65,6376,4114],{"class":248},[65,6378,349],{"class":75},[65,6380,4119],{"class":248},[65,6382,355],{"class":71},[65,6384,281],{"class":75},[65,6386,6388],{"class":67,"line":6387},48,[65,6389,564],{"class":75},[65,6391,6393],{"class":67,"line":6392},49,[65,6394,93],{"emptyLinePlaceholder":92},[65,6396,6398,6400,6402,6404,6406,6408,6410,6412,6414,6416,6418,6420,6422,6424,6426],{"class":67,"line":6397},50,[65,6399,6086],{"class":244},[65,6401,4292],{"class":255},[65,6403,259],{"class":75},[65,6405,4133],{"class":345},[65,6407,349],{"class":75},[65,6409,4114],{"class":345},[65,6411,349],{"class":75},[65,6413,4119],{"class":345},[65,6415,349],{"class":75},[65,6417,4309],{"class":345},[65,6419,349],{"class":75},[65,6421,4314],{"class":345},[65,6423,349],{"class":75},[65,6425,4319],{"class":345},[65,6427,4191],{"class":75},[65,6429,6431,6433,6435,6437,6439],{"class":67,"line":6430},51,[65,6432,6280],{"class":244},[65,6434,4328],{"class":248},[65,6436,336],{"class":75},[65,6438,4333],{"class":248},[65,6440,281],{"class":75},[65,6442,6444,6446,6448,6450,6452,6454,6456,6458],{"class":67,"line":6443},52,[65,6445,6320],{"class":248},[65,6447,425],{"class":75},[65,6449,4344],{"class":248},[65,6451,336],{"class":75},[65,6453,79],{"class":75},[65,6455,4351],{"class":82},[65,6457,313],{"class":75},[65,6459,281],{"class":75},[65,6461,6463,6465,6467,6469,6471],{"class":67,"line":6462},53,[65,6464,6320],{"class":248},[65,6466,425],{"class":75},[65,6468,4364],{"class":255},[65,6470,1208],{"class":71},[65,6472,281],{"class":75},[65,6474,6476,6478,6480,6482,6484,6486,6488,6490,6492],{"class":67,"line":6475},54,[65,6477,6320],{"class":248},[65,6479,425],{"class":75},[65,6481,4377],{"class":255},[65,6483,259],{"class":71},[65,6485,2988],{"class":460},[65,6487,349],{"class":75},[65,6489,4328],{"class":248},[65,6491,355],{"class":71},[65,6493,281],{"class":75},[65,6495,6497],{"class":67,"line":6496},55,[65,6498,93],{"emptyLinePlaceholder":92},[65,6500,6502,6505,6507,6509,6511,6513,6515,6517,6519,6521,6523,6525,6527,6529,6531,6533],{"class":67,"line":6501},56,[65,6503,6504],{"class":402},"            for",[65,6506,342],{"class":71},[65,6508,290],{"class":244},[65,6510,4405],{"class":248},[65,6512,252],{"class":75},[65,6514,2988],{"class":460},[65,6516,4412],{"class":75},[65,6518,4405],{"class":248},[65,6520,4417],{"class":75},[65,6522,4420],{"class":248},[65,6524,4412],{"class":75},[65,6526,4405],{"class":248},[65,6528,4427],{"class":75},[65,6530,4430],{"class":460},[65,6532,4433],{"class":71},[65,6534,406],{"class":75},[65,6536,6538,6541,6543,6545,6547,6549,6551,6553,6555,6557,6559,6561,6563,6565,6567,6569,6571,6573,6575,6577,6579,6581,6583],{"class":67,"line":6537},57,[65,6539,6540],{"class":244},"                var",[65,6542,4443],{"class":248},[65,6544,336],{"class":75},[65,6546,4448],{"class":75},[65,6548,4314],{"class":248},[65,6550,4453],{"class":75},[65,6552,4456],{"class":248},[65,6554,425],{"class":75},[65,6556,4461],{"class":255},[65,6558,4464],{"class":71},[65,6560,4456],{"class":248},[65,6562,425],{"class":75},[65,6564,4471],{"class":248},[65,6566,3355],{"class":75},[65,6568,4319],{"class":248},[65,6570,355],{"class":71},[65,6572,4453],{"class":75},[65,6574,259],{"class":71},[65,6576,4309],{"class":248},[65,6578,4486],{"class":75},[65,6580,4489],{"class":248},[65,6582,4492],{"class":71},[65,6584,281],{"class":75},[65,6586,6588,6591,6593,6595,6597,6599,6601,6603,6605,6607,6609],{"class":67,"line":6587},58,[65,6589,6590],{"class":248},"                ctx",[65,6592,425],{"class":75},[65,6594,4503],{"class":255},[65,6596,259],{"class":71},[65,6598,4489],{"class":248},[65,6600,349],{"class":75},[65,6602,4443],{"class":248},[65,6604,4486],{"class":75},[65,6606,4516],{"class":248},[65,6608,355],{"class":71},[65,6610,281],{"class":75},[65,6612,6614],{"class":67,"line":6613},59,[65,6615,3006],{"class":75},[65,6617,6619],{"class":67,"line":6618},60,[65,6620,93],{"emptyLinePlaceholder":92},[65,6622,6624,6626,6628,6630,6632,6634,6636,6638,6640],{"class":67,"line":6623},61,[65,6625,6320],{"class":248},[65,6627,425],{"class":75},[65,6629,4503],{"class":255},[65,6631,259],{"class":71},[65,6633,4114],{"class":248},[65,6635,349],{"class":75},[65,6637,4119],{"class":248},[65,6639,355],{"class":71},[65,6641,281],{"class":75},[65,6643,6645,6647,6649,6651,6653,6655,6657,6659,6661],{"class":67,"line":6644},62,[65,6646,6320],{"class":248},[65,6648,425],{"class":75},[65,6650,4503],{"class":255},[65,6652,259],{"class":71},[65,6654,2988],{"class":460},[65,6656,349],{"class":75},[65,6658,4119],{"class":248},[65,6660,355],{"class":71},[65,6662,281],{"class":75},[65,6664,6666,6668,6670,6672,6674],{"class":67,"line":6665},63,[65,6667,6320],{"class":248},[65,6669,425],{"class":75},[65,6671,4579],{"class":255},[65,6673,1208],{"class":71},[65,6675,281],{"class":75},[65,6677,6679],{"class":67,"line":6678},64,[65,6680,93],{"emptyLinePlaceholder":92},[65,6682,6684,6686,6688,6690,6692,6694,6696,6698,6700],{"class":67,"line":6683},65,[65,6685,6320],{"class":248},[65,6687,425],{"class":75},[65,6689,4599],{"class":248},[65,6691,336],{"class":75},[65,6693,79],{"class":75},[65,6695,4606],{"class":82},[65,6697,313],{"class":75},[65,6699,4412],{"class":75},[65,6701,4613],{"class":750},[65,6703,6705,6707,6709,6711,6713],{"class":67,"line":6704},66,[65,6706,6320],{"class":248},[65,6708,425],{"class":75},[65,6710,4623],{"class":255},[65,6712,1208],{"class":71},[65,6714,281],{"class":75},[65,6716,6718],{"class":67,"line":6717},67,[65,6719,564],{"class":75},[65,6721,6723],{"class":67,"line":6722},68,[65,6724,93],{"emptyLinePlaceholder":92},[65,6726,6728],{"class":67,"line":6727},69,[65,6729,3449],{"class":75},[65,6731,6733],{"class":67,"line":6732},70,[65,6734,570],{"class":75},[49,6736,6737],{"id":6737},"波の様子を変えたい場合",[11,6739,6740],{},"このコードの場合は",[32,6742,6744],{"className":2016,"code":6743,"language":2018,"meta":41,"style":41},"var amplitude = 30;\nvar period = 600;\n\nfunction loop(){\n      ...\n      degree += 12;\n      },30)\n}\n",[39,6745,6746,6758,6770,6774,6782,6787,6797,6806],{"__ignoreMap":41},[65,6747,6748,6750,6752,6754,6756],{"class":67,"line":68},[65,6749,290],{"class":244},[65,6751,4052],{"class":248},[65,6753,252],{"class":75},[65,6755,4057],{"class":460},[65,6757,281],{"class":75},[65,6759,6760,6762,6764,6766,6768],{"class":67,"line":89},[65,6761,290],{"class":244},[65,6763,4066],{"class":248},[65,6765,252],{"class":75},[65,6767,6062],{"class":460},[65,6769,281],{"class":75},[65,6771,6772],{"class":67,"line":96},[65,6773,93],{"emptyLinePlaceholder":92},[65,6775,6776,6778,6780],{"class":67,"line":105},[65,6777,3173],{"class":244},[65,6779,5559],{"class":255},[65,6781,3179],{"class":75},[65,6783,6784],{"class":67,"line":113},[65,6785,6786],{"class":75},"      ...\n",[65,6788,6789,6791,6793,6795],{"class":67,"line":124},[65,6790,5631],{"class":248},[65,6792,5634],{"class":75},[65,6794,5637],{"class":460},[65,6796,281],{"class":75},[65,6798,6799,6802,6804],{"class":67,"line":135},[65,6800,6801],{"class":75},"      },",[65,6803,5650],{"class":460},[65,6805,270],{"class":248},[65,6807,6808],{"class":67,"line":143},[65,6809,570],{"class":248},[11,6811,6812,6815,6816,6819,6820,6823,6824,6826],{},[39,6813,6814],{},"amplitude（振幅）","で波の最大の高さ、",[39,6817,6818],{},"period（周期）","で１波の周期、",[39,6821,6822],{},"degree +=","で波の速さを変化させることができます。他にも",[39,6825,4779],{},"で定義した三角関数の式を変えることで単純なサイン波でなく、複雑な波を描画できます。",[49,6828,6829],{"id":6829},"最後に",[11,6831,6832],{},"以上がcanvasを用いて画像をウネウネさせる方法です。canvasではこの様に複雑なアニメーションを用いた描画が可能です。jsで記述するのでFlashのActionScriptとかやっていた人は馴染みがあるかもしれません。",[808,6834,6835],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .s6YsC, html code.shiki .s6YsC{--shiki-default:#B2CCD6}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}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 pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":41,"searchDepth":96,"depth":96,"links":6837},[6838,6839,6842,6847,6855,6856,6857,6858],{"id":2805,"depth":89,"text":2805},{"id":2825,"depth":89,"text":2825,"children":6840},[6841],{"id":2863,"depth":96,"text":2864},{"id":2870,"depth":89,"text":2870,"children":6843},[6844],{"id":3160,"depth":96,"text":3160,"children":6845},[6846],{"id":3748,"depth":105,"text":3749},{"id":3944,"depth":89,"text":3944,"children":6848},[6849,6850],{"id":4652,"depth":96,"text":4653},{"id":4773,"depth":96,"text":4774,"children":6851},[6852,6853,6854],{"id":5128,"depth":105,"text":5129},{"id":5226,"depth":105,"text":5226},{"id":5469,"depth":105,"text":5469},{"id":5537,"depth":89,"text":5537},{"id":5719,"depth":89,"text":5719},{"id":6737,"depth":89,"text":6737},{"id":6829,"depth":89,"text":6829},[2188],"2026-03-04",{},"\u002Farticles\u002Fjs-canvas-wave",{"title":2786,"description":2786},"articles\u002Fjs-canvas-wave",[237],"_mix\u002Fex01-768x299.png","M7BMAJ4ad0W1ocZaATiSTEMNK1g6YP1t_HrYUpkyahQ",{"id":6869,"title":6870,"body":6871,"category":8521,"createdAt":8522,"description":8523,"extension":822,"index":823,"meta":8524,"navigation":92,"path":8525,"publish":92,"seo":8526,"series":823,"seriesTitle":823,"stem":8527,"tag":8528,"thumbnail":823,"updatedAt":8522,"__hash__":8530},"articles\u002Farticles\u002Fgithub-actions-node-js.md","Github Actionsを用いてVueファイルをビルド・rsyncで本番環境にデプロイする。",{"type":8,"value":6872,"toc":8500},[6873,6876,6879,6882,6885,6893,6897,6907,6910,6916,6919,6922,7149,7152,7155,7158,7161,7164,7170,7173,7176,7179,7198,7204,7219,7235,7238,7241,7248,7257,7260,7263,7276,7282,7288,7294,7300,7306,7312,7315,7321,7327,7330,7584,7590,7592,7600,7603,7606,7635,7649,7752,7766,7795,7798,7843,7850,7853,7860,7867,7902,7905,7944,7948,7951,8082,8093,8100,8130,8146,8191,8205,8216,8220,8223,8293,8296,8303,8307,8313,8380,8384,8394,8445,8455,8462,8465,8472,8476,8479,8482,8485,8488,8491,8494,8497],[11,6874,6875],{},"こんにちはjunです。皆さんはVueやReact、Nuxtなどなどフロントエンドフレームワークやライブラリを使っていますでしょうか？これらのライブラリはフロントの構築が楽になりますが、一度Node.jsを用いてビルドする必要があります。そしてビルドしたファイルを読み込ませることで動作します。",[11,6877,6878],{},"ローカルの環境ではNode.jsがあるので問題ないですが、デプロイする本番環境になくて困ったということはありませんでしょうか？サーバー要件などで本番環境にNode.jsを入れられない、無い場合は予めどこかでビルドして転送する必要があります。",[11,6880,6881],{},"一番手っ取り早いのはローカルでビルドしてFTPなりrsyncすることです。しかし何人もプロジェクトに関わっていたり、属人化したり、環境が統一されていないなど色々とデメリットがあります。",[11,6883,6884],{},"私はLaravel+Nuxt.jsなプロジェクトを開発し、Xserver（レンタルサーバー）に配置したことがあります。Laravelのアセットファイルと、Nuxt.jsはNode.jsでビルドする必要がありますが、レンタルサーバー にはNode.jsがありません。（Xserverには気合で入れらるらしいですが、、パフォーマンスなどの都合でやめました。）",[11,6886,6887,6888,6892],{},"そこで前から気になっていたGithub Actionsを用いてGithub上でビルドを行い、本番環境でrsyncすることでなんとかアセットファイル系がデプロイできました。今回はこの方法について解説します。前提やGithub Actionsの説明から行いますで、さっさと内部コードを知りたい方は「",[21,6889,6891],{"href":6890},"#%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%84%E3%81%8F","ワークフローを書いていく","」へ移動してください。",[49,6894,6896],{"id":6895},"github-actionsとは","Github Actionsとは",[6898,6899,6900],"blockquote",{},[11,6901,6902,6903,355],{},"GitHub Actionsを使用すると、ワールドクラスのCI \u002F CDですべてのソフトウェアワークフローを簡単に自動化できます。 GitHubから直接コードをビルド、テスト、デプロイでき、コードレビュー、ブランチ管理、問題のトリアージを希望どおりに機能させます。(",[21,6904,6905],{"href":6905,"rel":6906},"https:\u002F\u002Fgithub.co.jp\u002Ffeatures\u002Factions",[25],[11,6908,6909],{},"Github ActionsはGithubでビルド、テスト、デプロイ作業ができる環境です。Github上のコードを用いてすぐにビルドなどができます。例えばLaravelのVueファイルをビルドする際にはLaravelのプロジェクトルートで",[32,6911,6914],{"className":6912,"code":6913,"language":37},[35],"npm run prod\n",[39,6915,6913],{"__ignoreMap":41},[11,6917,6918],{},"とnode.jsのコマンドを打って、node.jsを動かしてビルドファイルを作成します。そしてビルド後にはcss,jsディレクトリが作成されます。このビルド操作をGithubの環境でも行えるようにします。",[11,6920,6921],{},"以下のようなymlファイルをGithub上で作成して、ビルド・やりたいコマンドを記述します。",[32,6923,6927],{"className":6924,"code":6925,"language":6926,"meta":41,"style":41},"language-yml shiki shiki-themes material-theme-ocean","name: Deploy\n\non: [ workflow_dispatch ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    \n    steps:\n    - uses: actions\u002Fcheckout@v2\n      with:\n        ref: release\n    - uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: '14'\n        cache: 'npm'\n     - name: public build\n      run: |\n        npm install\n        npm run prod\n        rsync -av --delete \\\n        .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n        deploy:$LARAVEL_PATH\u002Fpublic\u002F\n        scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n      env:\n        LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n","yml",[39,6928,6929,6939,6943,6959,6963,6970,6977,6981,6991,6995,7002,7015,7022,7032,7043,7049,7065,7079,7091,7101,7106,7111,7116,7121,7126,7131,7138],{"__ignoreMap":41},[65,6930,6931,6934,6936],{"class":67,"line":68},[65,6932,6933],{"class":71},"name",[65,6935,76],{"class":75},[65,6937,6938],{"class":82}," Deploy\n",[65,6940,6941],{"class":67,"line":89},[65,6942,93],{"emptyLinePlaceholder":92},[65,6944,6945,6948,6950,6953,6956],{"class":67,"line":96},[65,6946,6947],{"class":219},"on",[65,6949,76],{"class":75},[65,6951,6952],{"class":75}," [",[65,6954,6955],{"class":82}," workflow_dispatch",[65,6957,6958],{"class":75}," ]\n",[65,6960,6961],{"class":67,"line":105},[65,6962,93],{"emptyLinePlaceholder":92},[65,6964,6965,6968],{"class":67,"line":113},[65,6966,6967],{"class":71},"jobs",[65,6969,102],{"class":75},[65,6971,6972,6975],{"class":67,"line":124},[65,6973,6974],{"class":71},"  build",[65,6976,102],{"class":75},[65,6978,6979],{"class":67,"line":135},[65,6980,93],{"emptyLinePlaceholder":92},[65,6982,6983,6986,6988],{"class":67,"line":143},[65,6984,6985],{"class":71},"    runs-on",[65,6987,76],{"class":75},[65,6989,6990],{"class":82}," ubuntu-latest\n",[65,6992,6993],{"class":67,"line":152},[65,6994,3987],{"class":248},[65,6996,6997,7000],{"class":67,"line":163},[65,6998,6999],{"class":71},"    steps",[65,7001,102],{"class":75},[65,7003,7004,7007,7010,7012],{"class":67,"line":171},[65,7005,7006],{"class":75},"    -",[65,7008,7009],{"class":71}," uses",[65,7011,76],{"class":75},[65,7013,7014],{"class":82}," actions\u002Fcheckout@v2\n",[65,7016,7017,7020],{"class":67,"line":179},[65,7018,7019],{"class":71},"      with",[65,7021,102],{"class":75},[65,7023,7024,7027,7029],{"class":67,"line":187},[65,7025,7026],{"class":71},"        ref",[65,7028,76],{"class":75},[65,7030,7031],{"class":82}," release\n",[65,7033,7034,7036,7038,7040],{"class":67,"line":195},[65,7035,7006],{"class":75},[65,7037,7009],{"class":71},[65,7039,76],{"class":75},[65,7041,7042],{"class":82}," actions\u002Fsetup-node@v2\n",[65,7044,7045,7047],{"class":67,"line":203},[65,7046,7019],{"class":71},[65,7048,102],{"class":75},[65,7050,7051,7054,7056,7059,7062],{"class":67,"line":211},[65,7052,7053],{"class":71},"        node-version",[65,7055,76],{"class":75},[65,7057,7058],{"class":75}," '",[65,7060,7061],{"class":82},"14",[65,7063,7064],{"class":75},"'\n",[65,7066,7067,7070,7072,7074,7077],{"class":67,"line":466},[65,7068,7069],{"class":71},"        cache",[65,7071,76],{"class":75},[65,7073,7058],{"class":75},[65,7075,7076],{"class":82},"npm",[65,7078,7064],{"class":75},[65,7080,7081,7084,7086,7088],{"class":67,"line":496},[65,7082,7083],{"class":75},"     -",[65,7085,881],{"class":71},[65,7087,76],{"class":75},[65,7089,7090],{"class":82}," public build\n",[65,7092,7093,7096,7098],{"class":67,"line":502},[65,7094,7095],{"class":71},"      run",[65,7097,76],{"class":75},[65,7099,7100],{"class":402}," |\n",[65,7102,7103],{"class":67,"line":520},[65,7104,7105],{"class":82},"        npm install\n",[65,7107,7108],{"class":67,"line":527},[65,7109,7110],{"class":82},"        npm run prod\n",[65,7112,7113],{"class":67,"line":539},[65,7114,7115],{"class":82},"        rsync -av --delete \\\n",[65,7117,7118],{"class":67,"line":556},[65,7119,7120],{"class":82},"        .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n",[65,7122,7123],{"class":67,"line":561},[65,7124,7125],{"class":82},"        deploy:$LARAVEL_PATH\u002Fpublic\u002F\n",[65,7127,7128],{"class":67,"line":567},[65,7129,7130],{"class":82},"        scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n",[65,7132,7133,7136],{"class":67,"line":1343},[65,7134,7135],{"class":71},"      env",[65,7137,102],{"class":75},[65,7139,7140,7143,7146],{"class":67,"line":1872},[65,7141,7142],{"class":71},"        LARAVEL_PATH",[65,7144,7145],{"class":75}," :",[65,7147,7148],{"class":82}," ${{ secrets.LARAVEL_PATH }}\n",[11,7150,7151],{},"Dokcerファイルやバッチファイルと似た感じです。Node.jsの環境などはGithubが用意してくれます。",[597,7153,7154],{"id":7154},"使える言語など",[11,7156,7157],{},"結構なんでもいけます。Node.jsはしかり、PHP\u002FPython\u002FRuby\u002FJava\u002FPower Shellなど色々あります。",[597,7159,7160],{"id":7160},"料金",[11,7162,7163],{},"パブリックリポジトリの場合は何分使おうが無料です。しかしプライベートの場合は無料枠があり、フリーは毎月2000分までとなっています。(2022年1月時点)",[11,7165,7166,7167],{},"参照：",[21,7168,6905],{"href":6905,"rel":7169},[25],[11,7171,7172],{},"私のプロジェクトの場合、大体3分ぐらいで終わりますし、頻繁にビルドしないので基本無料で使えそうです。",[49,7174,7175],{"id":7175},"全体処理の概要とビルド対象",[11,7177,7178],{},"今回ビルドするプロジェクトはLaravelとNuxtが連携されたプロジェクトです。",[2228,7180,7181,7191],{},[2231,7182,7183,7184,349,7187,7190],{},"Laravelのresources配下に作ったsassとVueファイル。公開ディレクトリの",[39,7185,7186],{},"css\u002F",[39,7188,7189],{},"js\u002F","に吐き出される",[2231,7192,7193,7194,7197],{},"Nuxtの静的書き出しファイル。",[39,7195,7196],{},"dist\u002F","というディレクトリが生成される。",[32,7199,7202],{"className":7200,"code":7201,"language":37},[35],".\n├── README.md\n├── app\n├── artisan\n├── bootstrap\n├── composer.json\n├── composer.lock\n├── config\n├── database\n├── nuxt # nuxtはここ\n├── package-lock.json\n├── package.json\n├── phpunit.xml\n├── public # ここにLaravelのcss,jsが吐き出される\n├── resources\n├── routes\n├── server.php\n├── storage\n├── tests\n├── tinker_test.php\n└── webpack.mix.js\n",[39,7203,7201],{"__ignoreMap":41},[11,7205,7206,7207,7210,7211,7214,7215,7218],{},"まあとりあえず、Laravelルートで",[39,7208,7209],{},"npm run prod","そして、",[39,7212,7213],{},"nuxt\u002F","にて",[39,7216,7217],{},"npm run generate","してnode.jsを動かす必要があります。",[11,7220,7221,7222,349,7224,349,7226,349,7229,349,7232,7234],{},"そして生成されてた",[39,7223,7186],{},[39,7225,7189],{},[39,7227,7228],{},"images\u002F",[39,7230,7231],{},"mix-manifest.json",[39,7233,7196],{},"ディレクトリ・ファイルを本番サーバーに転送します。",[11,7236,7237],{},"転送の際にはrsyncを使用し、SSHの鍵認証で接続します。またこのアクションは手動で行うようにします。一応、masterブランチにプッシュされた時に自動で実行なんてこともできます。ただし今回はビルドする環境が欲しいだけなので、処理の実行は手動で行います。以上がActionの概要です。",[49,7239,7240],{"id":7240},"環境変数を定義しておく",[11,7242,7243,7244,7247],{},"まずSSHやビルドで使用する",[39,7245,7246],{},".env","など環境変数を定義しておきます。Github Actionsでも環境変数を定義できます。",[11,7249,7250,7251,7256],{},"リポジトリのSettingsから",[21,7252,7255],{"href":7253,"rel":7254},"https:\u002F\u002Fgithub.com\u002Fmedia-ch\u002Fsetagaya_foodshare\u002Fsettings\u002Fsecrets\u002Factions",[25],"Secrets","の画面で定義できます。",[1503,7258],{":src":7259,":width":1506},"'github-actions-node-js\u002Fsecrets-setting.png'",[11,7261,7262],{},"「New repository secret」をクリックしてキー名と値を入力します。",[11,7264,7265,7268,7269,3721,7272,7275],{},[2224,7266,7267],{},"SSH_KEY","：SSHに使用する鍵ファイルの中身です。",[39,7270,7271],{},".pem",[39,7273,7274],{},".key","などを開いて記述された文字をすべてコピペしてください。",[11,7277,7278,7281],{},[2224,7279,7280],{},"SSH_HOST","：接続先のホスト名です。",[11,7283,7284,7287],{},[2224,7285,7286],{},"SSH_PORT","：接続先のポートです。",[11,7289,7290,7293],{},[2224,7291,7292],{},"SSH_USER","：接続先のユーザーです。",[11,7295,7296,7299],{},[2224,7297,7298],{},"LARAEL_PATH","：本番サーバーでのLaravelが置かれている絶対パスです。",[11,7301,7302,7305],{},[2224,7303,7304],{},"GOOGLE_MAP_API_KEY","：NuxtでGoogleMapのAPI（フロントに出してもOKなやつ）を使っているので定義。あとで使います。",[11,7307,7308,7309,7311],{},"以上のSSHに関連する値と、",[39,7310,7246],{},"の記述で必要であれば書いておきます。それではアクションの内容を書いていきましょう。",[49,7313,7314],{"id":7314},"ワークフローを作成しテンプレートを選択する",[11,7316,7317,7318],{},"メニューの「Actions」をクリックしたのち、「New Workflow」をクリックします。\n",[1503,7319],{":src":7320},"'github-actions-node-js\u002Fmenu.png'",[11,7322,7323,7324],{},"するとworkflowを選択する画面にて、テンプレートをいくつか用意してくれています。\n",[1503,7325],{":src":7326},"'github-actions-node-js\u002Fworkflows.png'",[11,7328,7329],{},"今回はNode.jsのビルドしかないので「Node.js」を選択します。するとある程度の記述が書かれた状態で、yamlが表示されます。",[32,7331,7333],{"className":58,"code":7332,"language":61,"meta":41,"style":41},"# This workflow will do a clean installation of node dependencies, cache\u002Frestore them, build the source code and run tests across different versions of node\n# For more information see: https:\u002F\u002Fhelp.github.com\u002Factions\u002Flanguage-and-framework-guides\u002Fusing-nodejs-with-github-actions\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [12.x, 14.x, 16.x]\n        # See supported Node.js release schedule at https:\u002F\u002Fnodejs.org\u002Fen\u002Fabout\u002Freleases\u002F\n\n    steps:\n    - uses: actions\u002Fcheckout@v2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: ${{ matrix.node-version }}\n        cache: 'npm'\n    - run: npm ci\n    - run: npm run build --if-present\n    - run: npm test\n",[39,7334,7335,7340,7345,7349,7358,7362,7368,7375,7389,7396,7408,7412,7418,7424,7428,7436,7440,7447,7454,7478,7483,7487,7493,7503,7514,7523,7529,7538,7550,7562,7573],{"__ignoreMap":41},[65,7336,7337],{"class":67,"line":68},[65,7338,7339],{"class":750},"# This workflow will do a clean installation of node dependencies, cache\u002Frestore them, build the source code and run tests across different versions of node\n",[65,7341,7342],{"class":67,"line":89},[65,7343,7344],{"class":750},"# For more information see: https:\u002F\u002Fhelp.github.com\u002Factions\u002Flanguage-and-framework-guides\u002Fusing-nodejs-with-github-actions\n",[65,7346,7347],{"class":67,"line":96},[65,7348,93],{"emptyLinePlaceholder":92},[65,7350,7351,7353,7355],{"class":67,"line":105},[65,7352,6933],{"class":71},[65,7354,76],{"class":75},[65,7356,7357],{"class":82}," Node.js CI\n",[65,7359,7360],{"class":67,"line":113},[65,7361,93],{"emptyLinePlaceholder":92},[65,7363,7364,7366],{"class":67,"line":124},[65,7365,6947],{"class":219},[65,7367,102],{"class":75},[65,7369,7370,7373],{"class":67,"line":135},[65,7371,7372],{"class":71},"  push",[65,7374,102],{"class":75},[65,7376,7377,7380,7382,7384,7387],{"class":67,"line":143},[65,7378,7379],{"class":71},"    branches",[65,7381,76],{"class":75},[65,7383,6952],{"class":75},[65,7385,7386],{"class":82}," master",[65,7388,6958],{"class":75},[65,7390,7391,7394],{"class":67,"line":152},[65,7392,7393],{"class":71},"  pull_request",[65,7395,102],{"class":75},[65,7397,7398,7400,7402,7404,7406],{"class":67,"line":163},[65,7399,7379],{"class":71},[65,7401,76],{"class":75},[65,7403,6952],{"class":75},[65,7405,7386],{"class":82},[65,7407,6958],{"class":75},[65,7409,7410],{"class":67,"line":171},[65,7411,93],{"emptyLinePlaceholder":92},[65,7413,7414,7416],{"class":67,"line":179},[65,7415,6967],{"class":71},[65,7417,102],{"class":75},[65,7419,7420,7422],{"class":67,"line":187},[65,7421,6974],{"class":71},[65,7423,102],{"class":75},[65,7425,7426],{"class":67,"line":195},[65,7427,93],{"emptyLinePlaceholder":92},[65,7429,7430,7432,7434],{"class":67,"line":203},[65,7431,6985],{"class":71},[65,7433,76],{"class":75},[65,7435,6990],{"class":82},[65,7437,7438],{"class":67,"line":211},[65,7439,93],{"emptyLinePlaceholder":92},[65,7441,7442,7445],{"class":67,"line":466},[65,7443,7444],{"class":71},"    strategy",[65,7446,102],{"class":75},[65,7448,7449,7452],{"class":67,"line":496},[65,7450,7451],{"class":71},"      matrix",[65,7453,102],{"class":75},[65,7455,7456,7458,7460,7462,7465,7467,7470,7472,7475],{"class":67,"line":502},[65,7457,7053],{"class":71},[65,7459,76],{"class":75},[65,7461,6952],{"class":75},[65,7463,7464],{"class":82},"12.x",[65,7466,349],{"class":75},[65,7468,7469],{"class":82}," 14.x",[65,7471,349],{"class":75},[65,7473,7474],{"class":82}," 16.x",[65,7476,7477],{"class":75},"]\n",[65,7479,7480],{"class":67,"line":520},[65,7481,7482],{"class":750},"        # See supported Node.js release schedule at https:\u002F\u002Fnodejs.org\u002Fen\u002Fabout\u002Freleases\u002F\n",[65,7484,7485],{"class":67,"line":527},[65,7486,93],{"emptyLinePlaceholder":92},[65,7488,7489,7491],{"class":67,"line":539},[65,7490,6999],{"class":71},[65,7492,102],{"class":75},[65,7494,7495,7497,7499,7501],{"class":67,"line":556},[65,7496,7006],{"class":75},[65,7498,7009],{"class":71},[65,7500,76],{"class":75},[65,7502,7014],{"class":82},[65,7504,7505,7507,7509,7511],{"class":67,"line":561},[65,7506,7006],{"class":75},[65,7508,881],{"class":71},[65,7510,76],{"class":75},[65,7512,7513],{"class":82}," Use Node.js ${{ matrix.node-version }}\n",[65,7515,7516,7519,7521],{"class":67,"line":567},[65,7517,7518],{"class":71},"      uses",[65,7520,76],{"class":75},[65,7522,7042],{"class":82},[65,7524,7525,7527],{"class":67,"line":1343},[65,7526,7019],{"class":71},[65,7528,102],{"class":75},[65,7530,7531,7533,7535],{"class":67,"line":1872},[65,7532,7053],{"class":71},[65,7534,76],{"class":75},[65,7536,7537],{"class":82}," ${{ matrix.node-version }}\n",[65,7539,7540,7542,7544,7546,7548],{"class":67,"line":1901},[65,7541,7069],{"class":71},[65,7543,76],{"class":75},[65,7545,7058],{"class":75},[65,7547,7076],{"class":82},[65,7549,7064],{"class":75},[65,7551,7552,7554,7557,7559],{"class":67,"line":1930},[65,7553,7006],{"class":75},[65,7555,7556],{"class":71}," run",[65,7558,76],{"class":75},[65,7560,7561],{"class":82}," npm ci\n",[65,7563,7564,7566,7568,7570],{"class":67,"line":1959},[65,7565,7006],{"class":75},[65,7567,7556],{"class":71},[65,7569,76],{"class":75},[65,7571,7572],{"class":82}," npm run build --if-present\n",[65,7574,7575,7577,7579,7581],{"class":67,"line":1966},[65,7576,7006],{"class":75},[65,7578,7556],{"class":71},[65,7580,76],{"class":75},[65,7582,7583],{"class":82}," npm test\n",[11,7585,7586,7587,7589],{},"最初は上記の構成となっています。",[39,7588,6933],{},"はワークフローの名前になります。わかりやすいものに変えておきましょう。",[49,7591,6891],{"id":6891},[11,7593,7594,7595],{},"まず最初にLaravelのアセットファイルを作成してrsyncするとこまで記述します。なお登場する記述に関してはこちらの公式ドキュメントを参考にしてください。",[21,7596,7599],{"href":7597,"rel":7598},"https:\u002F\u002Fdocs.github.com\u002Fja\u002Factions\u002Fusing-workflows\u002Fworkflow-syntax-for-github-actions",[25],"ワークフロー構文",[597,7601,7602],{"id":7602},"実行条件などの変更",[11,7604,7605],{},"最初は実行条件などを変更します。",[32,7607,7609],{"className":58,"code":7608,"language":61,"meta":41,"style":41},"name: Deploy\n\non: [ workflow_dispatch ]\n",[39,7610,7611,7619,7623],{"__ignoreMap":41},[65,7612,7613,7615,7617],{"class":67,"line":68},[65,7614,6933],{"class":71},[65,7616,76],{"class":75},[65,7618,6938],{"class":82},[65,7620,7621],{"class":67,"line":89},[65,7622,93],{"emptyLinePlaceholder":92},[65,7624,7625,7627,7629,7631,7633],{"class":67,"line":96},[65,7626,6947],{"class":219},[65,7628,76],{"class":75},[65,7630,6952],{"class":75},[65,7632,6955],{"class":82},[65,7634,6958],{"class":75},[11,7636,7637,7640,7641,7644,7645,7648],{},[39,7638,7639],{},"on:","はこのワークフローの実行条件です。デフォルトでは",[39,7642,7643],{},"master","ブランチにpushされることが条件ですが、ここでは",[39,7646,7647],{},"workflow_dispatch","として、手動で実行できるようにします。",[32,7650,7652],{"className":58,"code":7651,"language":61,"meta":41,"style":41},"jobs:\n  build:\n\n    runs-on: ubuntu-latest\n    \n    steps:\n    - uses: actions\u002Fcheckout@v2\n      with:\n        ref: release\n    - uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: '14'\n        cache: 'npm'\n",[39,7653,7654,7660,7666,7670,7678,7682,7688,7698,7704,7712,7722,7728,7740],{"__ignoreMap":41},[65,7655,7656,7658],{"class":67,"line":68},[65,7657,6967],{"class":71},[65,7659,102],{"class":75},[65,7661,7662,7664],{"class":67,"line":89},[65,7663,6974],{"class":71},[65,7665,102],{"class":75},[65,7667,7668],{"class":67,"line":96},[65,7669,93],{"emptyLinePlaceholder":92},[65,7671,7672,7674,7676],{"class":67,"line":105},[65,7673,6985],{"class":71},[65,7675,76],{"class":75},[65,7677,6990],{"class":82},[65,7679,7680],{"class":67,"line":113},[65,7681,3987],{"class":248},[65,7683,7684,7686],{"class":67,"line":124},[65,7685,6999],{"class":71},[65,7687,102],{"class":75},[65,7689,7690,7692,7694,7696],{"class":67,"line":135},[65,7691,7006],{"class":75},[65,7693,7009],{"class":71},[65,7695,76],{"class":75},[65,7697,7014],{"class":82},[65,7699,7700,7702],{"class":67,"line":143},[65,7701,7019],{"class":71},[65,7703,102],{"class":75},[65,7705,7706,7708,7710],{"class":67,"line":152},[65,7707,7026],{"class":71},[65,7709,76],{"class":75},[65,7711,7031],{"class":82},[65,7713,7714,7716,7718,7720],{"class":67,"line":163},[65,7715,7006],{"class":75},[65,7717,7009],{"class":71},[65,7719,76],{"class":75},[65,7721,7042],{"class":82},[65,7723,7724,7726],{"class":67,"line":171},[65,7725,7019],{"class":71},[65,7727,102],{"class":75},[65,7729,7730,7732,7734,7736,7738],{"class":67,"line":179},[65,7731,7053],{"class":71},[65,7733,76],{"class":75},[65,7735,7058],{"class":75},[65,7737,7061],{"class":82},[65,7739,7064],{"class":75},[65,7741,7742,7744,7746,7748,7750],{"class":67,"line":187},[65,7743,7069],{"class":71},[65,7745,76],{"class":75},[65,7747,7058],{"class":75},[65,7749,7076],{"class":82},[65,7751,7064],{"class":75},[11,7753,7754,7755,7758,7759,7761,7762,7765],{},"このリポジトリの場合、本番環境は常に",[39,7756,7757],{},"release","ブランチをプルするのでビルド対象ファイルも",[39,7760,7757],{},"のものを使用します。そのため",[39,7763,7764],{},"- uses: actions\u002Fcheckout@v2","というブランチのチェックアウトが処理を行う記述をします。",[32,7767,7769],{"className":58,"code":7768,"language":61,"meta":41,"style":41},"    - uses: actions\u002Fcheckout@v2\n      with:\n        ref: release\n",[39,7770,7771,7781,7787],{"__ignoreMap":41},[65,7772,7773,7775,7777,7779],{"class":67,"line":68},[65,7774,7006],{"class":75},[65,7776,7009],{"class":71},[65,7778,76],{"class":75},[65,7780,7014],{"class":82},[65,7782,7783,7785],{"class":67,"line":89},[65,7784,7019],{"class":71},[65,7786,102],{"class":75},[65,7788,7789,7791,7793],{"class":67,"line":96},[65,7790,7026],{"class":71},[65,7792,76],{"class":75},[65,7794,7031],{"class":82},[11,7796,7797],{},"これでリリースブランチにチェックアウトしてビルドできるようになります。",[32,7799,7801],{"className":58,"code":7800,"language":61,"meta":41,"style":41},"- uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: '14'\n        cache: 'npm'\n",[39,7802,7803,7813,7819,7831],{"__ignoreMap":41},[65,7804,7805,7807,7809,7811],{"class":67,"line":68},[65,7806,4036],{"class":75},[65,7808,7009],{"class":71},[65,7810,76],{"class":75},[65,7812,7042],{"class":82},[65,7814,7815,7817],{"class":67,"line":89},[65,7816,7019],{"class":71},[65,7818,102],{"class":75},[65,7820,7821,7823,7825,7827,7829],{"class":67,"line":96},[65,7822,7053],{"class":71},[65,7824,76],{"class":75},[65,7826,7058],{"class":75},[65,7828,7061],{"class":82},[65,7830,7064],{"class":75},[65,7832,7833,7835,7837,7839,7841],{"class":67,"line":105},[65,7834,7069],{"class":71},[65,7836,76],{"class":75},[65,7838,7058],{"class":75},[65,7840,7076],{"class":82},[65,7842,7064],{"class":75},[11,7844,7845,7846,7849],{},"これでNode.js14の環境を使用できるようになり、npmコマンドも使用できるようになります。それでは",[39,7847,7848],{},"step:","配下に実行するコマンドを書いていきましょう。",[597,7851,7852],{"id":7852},"実行コードの書き方",[11,7854,7855,7856,7859],{},"実行コードは",[39,7857,7858],{},"name:","を用いて区分けできます。長いと何がなんだか分からなくなるので、書いておくといいです。",[11,7861,7862,7863,7866],{},"そして実行内容は",[39,7864,7865],{},"run:","に記述します。",[32,7868,7870],{"className":58,"code":7869,"language":61,"meta":41,"style":41},"    - run: npm ci\n    - run: npm run build --if-present\n    - run: npm test\n",[39,7871,7872,7882,7892],{"__ignoreMap":41},[65,7873,7874,7876,7878,7880],{"class":67,"line":68},[65,7875,7006],{"class":75},[65,7877,7556],{"class":71},[65,7879,76],{"class":75},[65,7881,7561],{"class":82},[65,7883,7884,7886,7888,7890],{"class":67,"line":89},[65,7885,7006],{"class":75},[65,7887,7556],{"class":71},[65,7889,76],{"class":75},[65,7891,7572],{"class":82},[65,7893,7894,7896,7898,7900],{"class":67,"line":96},[65,7895,7006],{"class":75},[65,7897,7556],{"class":71},[65,7899,76],{"class":75},[65,7901,7583],{"class":82},[11,7903,7904],{},"のように１つづつ書いてもいいですが、ここでは以下のようにまとめて書くことにします。",[32,7906,7908],{"className":58,"code":7907,"language":61,"meta":41,"style":41},"    - name: ssh key generate\n      run: |\n        echo \"$SSH_KEY\" > id_rsa\n        mkdir ~\u002F.ssh\n        chmod 700 ~\u002F.ssh\n",[39,7909,7910,7921,7929,7934,7939],{"__ignoreMap":41},[65,7911,7912,7914,7916,7918],{"class":67,"line":68},[65,7913,7006],{"class":75},[65,7915,881],{"class":71},[65,7917,76],{"class":75},[65,7919,7920],{"class":82}," ssh key generate\n",[65,7922,7923,7925,7927],{"class":67,"line":89},[65,7924,7095],{"class":71},[65,7926,76],{"class":75},[65,7928,7100],{"class":402},[65,7930,7931],{"class":67,"line":96},[65,7932,7933],{"class":82},"        echo \"$SSH_KEY\" > id_rsa\n",[65,7935,7936],{"class":67,"line":105},[65,7937,7938],{"class":82},"        mkdir ~\u002F.ssh\n",[65,7940,7941],{"class":67,"line":113},[65,7942,7943],{"class":82},"        chmod 700 ~\u002F.ssh\n",[597,7945,7947],{"id":7946},"sshの設定","SSHの設定",[11,7949,7950],{},"そんでは最初にSSHの設定を行います。毎回、鍵のパスとかを記述するのは面倒なのでSSHのconfigファイルを作ってエイリアスで呼べるようにしましょう。",[32,7952,7954],{"className":58,"code":7953,"language":61,"meta":41,"style":41},"    - name: ssh key generate\n      run: |\n        echo \"$SSH_KEY\" > id_rsa\n        mkdir ~\u002F.ssh\n        chmod 700 ~\u002F.ssh\n        mv id_rsa ~\u002F.ssh\u002F\n        chmod 600 ~\u002F.ssh\u002Fid_rsa\n        echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\n        echo \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\n        echo \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\n        echo \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\n        echo \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\n        echo \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\n        echo \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\n        chmod 644 ~\u002F.ssh\u002Fconfig\n      env:\n        SSH_KEY: ${{ secrets.SSH_KEY }}\n        SSH_HOST: ${{ secrets.SSH_HOST }}\n        SSH_USER: ${{ secrets.SSH_USER }}\n        SSH_PORT: ${{ secrets.SSH_PORT }}\n",[39,7955,7956,7966,7974,7978,7982,7986,7991,7996,8001,8006,8011,8016,8021,8026,8031,8036,8042,8052,8062,8072],{"__ignoreMap":41},[65,7957,7958,7960,7962,7964],{"class":67,"line":68},[65,7959,7006],{"class":75},[65,7961,881],{"class":71},[65,7963,76],{"class":75},[65,7965,7920],{"class":82},[65,7967,7968,7970,7972],{"class":67,"line":89},[65,7969,7095],{"class":71},[65,7971,76],{"class":75},[65,7973,7100],{"class":402},[65,7975,7976],{"class":67,"line":96},[65,7977,7933],{"class":82},[65,7979,7980],{"class":67,"line":105},[65,7981,7938],{"class":82},[65,7983,7984],{"class":67,"line":113},[65,7985,7943],{"class":82},[65,7987,7988],{"class":67,"line":124},[65,7989,7990],{"class":82},"        mv id_rsa ~\u002F.ssh\u002F\n",[65,7992,7993],{"class":67,"line":135},[65,7994,7995],{"class":82},"        chmod 600 ~\u002F.ssh\u002Fid_rsa\n",[65,7997,7998],{"class":67,"line":143},[65,7999,8000],{"class":82},"        echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\n",[65,8002,8003],{"class":67,"line":152},[65,8004,8005],{"class":82},"        echo \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\n",[65,8007,8008],{"class":67,"line":163},[65,8009,8010],{"class":82},"        echo \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\n",[65,8012,8013],{"class":67,"line":171},[65,8014,8015],{"class":82},"        echo \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\n",[65,8017,8018],{"class":67,"line":179},[65,8019,8020],{"class":82},"        echo \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\n",[65,8022,8023],{"class":67,"line":187},[65,8024,8025],{"class":82},"        echo \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\n",[65,8027,8028],{"class":67,"line":195},[65,8029,8030],{"class":82},"        echo \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\n",[65,8032,8033],{"class":67,"line":203},[65,8034,8035],{"class":82},"        chmod 644 ~\u002F.ssh\u002Fconfig\n",[65,8037,8038,8040],{"class":67,"line":211},[65,8039,7135],{"class":71},[65,8041,102],{"class":75},[65,8043,8044,8047,8049],{"class":67,"line":466},[65,8045,8046],{"class":71},"        SSH_KEY",[65,8048,76],{"class":75},[65,8050,8051],{"class":82}," ${{ secrets.SSH_KEY }}\n",[65,8053,8054,8057,8059],{"class":67,"line":496},[65,8055,8056],{"class":71},"        SSH_HOST",[65,8058,76],{"class":75},[65,8060,8061],{"class":82}," ${{ secrets.SSH_HOST }}\n",[65,8063,8064,8067,8069],{"class":67,"line":502},[65,8065,8066],{"class":71},"        SSH_USER",[65,8068,76],{"class":75},[65,8070,8071],{"class":82}," ${{ secrets.SSH_USER }}\n",[65,8073,8074,8077,8079],{"class":67,"line":520},[65,8075,8076],{"class":71},"        SSH_PORT",[65,8078,76],{"class":75},[65,8080,8081],{"class":82}," ${{ secrets.SSH_PORT }}\n",[11,8083,8084,8085,8088,8089,8092],{},"まず",[39,8086,8087],{},"env:","にて使用する環境変数をコマンド変数に渡します。こうすることでコマンド内で",[39,8090,8091],{},"$SSH_KEY","として値を使用できます。キー、ホスト、ユーザー、ポートを出します。",[11,8094,8095,8096,8099],{},"ちなみに",[39,8097,8098],{},"${{ secrets.SSH_KEY }}","の記述はコンテキストと呼ばれています。ワークフローに関する情報やsecretsに保存した値にアクセスできます。",[32,8101,8103],{"className":58,"code":8102,"language":61,"meta":41,"style":41},"echo \"$SSH_KEY\" > id_rsa\nmkdir ~\u002F.ssh\nchmod 700 ~\u002F.ssh\nmv id_rsa ~\u002F.ssh\u002F\nchmod 600 ~\u002F.ssh\u002Fid_rsa\n",[39,8104,8105,8110,8115,8120,8125],{"__ignoreMap":41},[65,8106,8107],{"class":67,"line":68},[65,8108,8109],{"class":82},"echo \"$SSH_KEY\" > id_rsa\n",[65,8111,8112],{"class":67,"line":89},[65,8113,8114],{"class":82},"mkdir ~\u002F.ssh\n",[65,8116,8117],{"class":67,"line":96},[65,8118,8119],{"class":82},"chmod 700 ~\u002F.ssh\n",[65,8121,8122],{"class":67,"line":105},[65,8123,8124],{"class":82},"mv id_rsa ~\u002F.ssh\u002F\n",[65,8126,8127],{"class":67,"line":113},[65,8128,8129],{"class":82},"chmod 600 ~\u002F.ssh\u002Fid_rsa\n",[11,8131,8084,8132,1497,8134,8137,8138,8141,8142,8145],{},[39,8133,8091],{},[39,8135,8136],{},"id_rsa","としてファイルに出力。そして",[39,8139,8140],{},"~\u002F.ssh","ディレクトリを作成してその配下に置いておきます。鍵と",[39,8143,8144],{},".ssh","ディレクトリの権限変更を忘れないようにしてください。",[32,8147,8149],{"className":58,"code":8148,"language":61,"meta":41,"style":41},"echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\necho \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\necho \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\necho \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\necho \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\necho \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\necho \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\nchmod 644 ~\u002F.ssh\u002Fconfig\n",[39,8150,8151,8156,8161,8166,8171,8176,8181,8186],{"__ignoreMap":41},[65,8152,8153],{"class":67,"line":68},[65,8154,8155],{"class":82},"echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\n",[65,8157,8158],{"class":67,"line":89},[65,8159,8160],{"class":82},"echo \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\n",[65,8162,8163],{"class":67,"line":96},[65,8164,8165],{"class":82},"echo \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\n",[65,8167,8168],{"class":67,"line":105},[65,8169,8170],{"class":82},"echo \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\n",[65,8172,8173],{"class":67,"line":113},[65,8174,8175],{"class":82},"echo \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\n",[65,8177,8178],{"class":67,"line":124},[65,8179,8180],{"class":82},"echo \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\n",[65,8182,8183],{"class":67,"line":135},[65,8184,8185],{"class":82},"echo \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\n",[65,8187,8188],{"class":67,"line":143},[65,8189,8190],{"class":82},"chmod 644 ~\u002F.ssh\u002Fconfig\n",[11,8192,8193,8196,8197,8200,8201,8204],{},[39,8194,8195],{},"~\u002F.ssh\u002Fconfig","ファイルにエイリアスの記述を書いておきます。SSHは初回接続時に警告をだすので",[39,8198,8199],{},"StrictHostKeyChecking no","を設定し、known_hostsを出さないように",[39,8202,8203],{},"UserKnownHostsFile=\u002Fdev\u002Fnull","としておきます。",[11,8206,8207,8208,8211,8212,8215],{},"最後に権限をきちんと設定すれば、",[39,8209,8210],{},"deploy","というSSHエイリアスが使える用意なります。手動で",[39,8213,8214],{},".ssh\u002Fconfig","の設定をしていたのを自動化した感じです。",[597,8217,8219],{"id":8218},"ビルド処理rsync処理を記述","ビルド処理・rsync処理を記述",[11,8221,8222],{},"SSHの設定はできたのでLaravelのアセットビルドをするコードを書きます。",[32,8224,8226],{"className":58,"code":8225,"language":61,"meta":41,"style":41},"- name: public build\n  run: |\n    npm install\n    npm run prod\n    rsync -av --delete \\\n    .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n    deploy:$LARAVEL_PATH\u002Fpublic\u002F\n    scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n  env:\n    LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n",[39,8227,8228,8238,8247,8252,8257,8262,8267,8272,8277,8284],{"__ignoreMap":41},[65,8229,8230,8232,8234,8236],{"class":67,"line":68},[65,8231,4036],{"class":75},[65,8233,881],{"class":71},[65,8235,76],{"class":75},[65,8237,7090],{"class":82},[65,8239,8240,8243,8245],{"class":67,"line":89},[65,8241,8242],{"class":71},"  run",[65,8244,76],{"class":75},[65,8246,7100],{"class":402},[65,8248,8249],{"class":67,"line":96},[65,8250,8251],{"class":82},"    npm install\n",[65,8253,8254],{"class":67,"line":105},[65,8255,8256],{"class":82},"    npm run prod\n",[65,8258,8259],{"class":67,"line":113},[65,8260,8261],{"class":82},"    rsync -av --delete \\\n",[65,8263,8264],{"class":67,"line":124},[65,8265,8266],{"class":82},"    .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n",[65,8268,8269],{"class":67,"line":135},[65,8270,8271],{"class":82},"    deploy:$LARAVEL_PATH\u002Fpublic\u002F\n",[65,8273,8274],{"class":67,"line":143},[65,8275,8276],{"class":82},"    scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n",[65,8278,8279,8282],{"class":67,"line":152},[65,8280,8281],{"class":71},"  env",[65,8283,102],{"class":75},[65,8285,8286,8289,8291],{"class":67,"line":163},[65,8287,8288],{"class":71},"    LARAVEL_PATH",[65,8290,7145],{"class":75},[65,8292,7148],{"class":82},[11,8294,8295],{},"ワークフローの初期位置はリポジトリルートと対応しています。最初にライブラリなどをインストールしてからビルドします。",[11,8297,8298,8299,8302],{},"終わったらrsyncを行います。エイリアスを定義しておいたので",[39,8300,8301],{},"deploy:$LARAVEL_PATH\u002Fpublic\u002F","と簡単な記述で済みます。",[597,8304,8306],{"id":8305},"nuxtjsのビルド処理を記述する","Nuxt.jsのビルド処理を記述する",[11,8308,8309,8310,8312],{},"次に",[39,8311,7213],{},"に移動してnuxt.jsのビルド処理を記述します。",[32,8314,8316],{"className":58,"code":8315,"language":61,"meta":41,"style":41},"    - name: nuxt build\n      run: |\n        cd nuxt\n        touch .env\n        echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env\n        npm install\n        npm run generate\n        rsync -av --delete .\u002Fdist deploy:$LARAVEL_PATH\u002Fnuxt\u002F\n      env:\n        LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n",[39,8317,8318,8329,8337,8342,8347,8352,8356,8361,8366,8372],{"__ignoreMap":41},[65,8319,8320,8322,8324,8326],{"class":67,"line":68},[65,8321,7006],{"class":75},[65,8323,881],{"class":71},[65,8325,76],{"class":75},[65,8327,8328],{"class":82}," nuxt build\n",[65,8330,8331,8333,8335],{"class":67,"line":89},[65,8332,7095],{"class":71},[65,8334,76],{"class":75},[65,8336,7100],{"class":402},[65,8338,8339],{"class":67,"line":96},[65,8340,8341],{"class":82},"        cd nuxt\n",[65,8343,8344],{"class":67,"line":105},[65,8345,8346],{"class":82},"        touch .env\n",[65,8348,8349],{"class":67,"line":113},[65,8350,8351],{"class":82},"        echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env\n",[65,8353,8354],{"class":67,"line":124},[65,8355,7105],{"class":82},[65,8357,8358],{"class":67,"line":135},[65,8359,8360],{"class":82},"        npm run generate\n",[65,8362,8363],{"class":67,"line":143},[65,8364,8365],{"class":82},"        rsync -av --delete .\u002Fdist deploy:$LARAVEL_PATH\u002Fnuxt\u002F\n",[65,8367,8368,8370],{"class":67,"line":152},[65,8369,7135],{"class":71},[65,8371,102],{"class":75},[65,8373,8374,8376,8378],{"class":67,"line":163},[65,8375,7142],{"class":71},[65,8377,7145],{"class":75},[65,8379,7148],{"class":82},[2326,8381,8383],{"id":8382},"envファイルを使うには",".envファイルを使うには",[11,8385,8386,8387,8389,8390,8393],{},"プロジェクトによっては",[39,8388,7246],{},"ファイルを使用して端末ごとに環境変数を定義していると思います。.envは大体",[39,8391,8392],{},"gitignore","されてバージョン管理されていないので、ワークフローないで作成します。",[32,8395,8397],{"className":58,"code":8396,"language":61,"meta":41,"style":41},"      run: |\n        cd nuxt\n        touch .env\n        echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env\n        npm install\n        npm run generate\n        rsync -av --delete .\u002Fdist deploy:$LARAVEL_PATH\u002Fnuxt\u002F\n      env:\n        LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n",[39,8398,8399,8407,8411,8415,8419,8423,8427,8431,8437],{"__ignoreMap":41},[65,8400,8401,8403,8405],{"class":67,"line":68},[65,8402,7095],{"class":71},[65,8404,76],{"class":75},[65,8406,7100],{"class":402},[65,8408,8409],{"class":67,"line":89},[65,8410,8341],{"class":82},[65,8412,8413],{"class":67,"line":96},[65,8414,8346],{"class":82},[65,8416,8417],{"class":67,"line":105},[65,8418,8351],{"class":82},[65,8420,8421],{"class":67,"line":113},[65,8422,7105],{"class":82},[65,8424,8425],{"class":67,"line":124},[65,8426,8360],{"class":82},[65,8428,8429],{"class":67,"line":135},[65,8430,8365],{"class":82},[65,8432,8433,8435],{"class":67,"line":143},[65,8434,7135],{"class":71},[65,8436,102],{"class":75},[65,8438,8439,8441,8443],{"class":67,"line":152},[65,8440,7142],{"class":71},[65,8442,7145],{"class":75},[65,8444,7148],{"class":82},[11,8446,8447,8448,8450,8451,8454],{},"と必要な箇所で",[39,8449,7246],{},"ファイルを作って、",[39,8452,8453],{},"echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env","とGithubの環境変数内容を出力します。これでOKです。",[11,8456,8457,8458,8461],{},"nuxtは静的書出すると",[39,8459,8460],{},"dist","が作成されるので、rsyncで転送します。",[597,8463,8464],{"id":8464},"保存する",[11,8466,8467,8468,8471],{},"記述が終わったら画面右上の「Start Commit」をおして内容をコミットします。ちなみにワークフローファイルはリポジトリの",[39,8469,8470],{},".github\u002Fworkflows","というディレクトリが作られ、そこに保存されます。",[49,8473,8475],{"id":8474},"全ビルドを実行手動","全ビルドを実行（手動）",[11,8477,8478],{},"ではビルドしましょう。Actionsで対象のデプロイ名を選択して「Run Workflow」を押して、対象ブランチを選択して実行します。",[1503,8480],{":src":8481},"'github-actions-node-js\u002Fdispatch-job.png'",[11,8483,8484],{},"ビルド中の様子やログは随時確認することができます。ビルドが無事に終了すると以下のように全てチェックマークとなり、処理が終了します。どこかエラーが起きた場合はそこで処理が中止されます。",[1503,8486],{":src":8487},"'github-actions-node-js\u002Fsuccess.png'",[11,8489,8490],{},"終わったら本番サーバーで対象のファイルが作られているかなどを確認してみましょう。",[49,8492,8493],{"id":8493},"使ってみた感想",[11,8495,8496],{},"少人数でこれぐらいであればローカルPCで誰でもできそうですが、ボタンひとつでビルドできるようになることや手違いもなくなるのでとてもおすすめです。色々自動化できるようにGithub Actionsを色々探ってみます。",[808,8498,8499],{},"html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}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 pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":41,"searchDepth":96,"depth":96,"links":8501},[8502,8506,8507,8508,8509,8519,8520],{"id":6895,"depth":89,"text":6896,"children":8503},[8504,8505],{"id":7154,"depth":96,"text":7154},{"id":7160,"depth":96,"text":7160},{"id":7175,"depth":89,"text":7175},{"id":7240,"depth":89,"text":7240},{"id":7314,"depth":89,"text":7314},{"id":6891,"depth":89,"text":6891,"children":8510},[8511,8512,8513,8514,8515,8518],{"id":7602,"depth":96,"text":7602},{"id":7852,"depth":96,"text":7852},{"id":7946,"depth":96,"text":7947},{"id":8218,"depth":96,"text":8219},{"id":8305,"depth":96,"text":8306,"children":8516},[8517],{"id":8382,"depth":105,"text":8383},{"id":8464,"depth":96,"text":8464},{"id":8474,"depth":89,"text":8475},{"id":8493,"depth":89,"text":8493},[2188],"2026-02-11","not node.jsな環境でアセットをビルドして転送する。",{},"\u002Farticles\u002Fgithub-actions-node-js",{"title":6870,"description":8523},"articles\u002Fgithub-actions-node-js",[2781,8529],"node","tRNfJ9LFek0TNwphGk2rKIZmRCAhyvmVgSvx-MGlLXE",1780987130056]