1import{_ as s,L as u}from"./q-D55dtAdB.js";import{A as h,g as r,s as g,p as m}from"./q-COPPcY2F.js";import{f as l,v as o,G as v,l as a,q as i,N as c,j as n,_hW as f}from"./q-CVlCxsCm.js";import{S as w}from"./q-BFzYU5nr.js";const b="/assets/ChhwydQg-Slava_Chub.webp 140w",k=140,y=140,_={srcSet:b,width:k,height:y};function S(e,t,d,p){return l("img",{decoding:"async",loading:"lazy",...e},_,void 0,3,t)}const T="/assets/DF4NqR-z-game_n_qwik_part2_main.webp 200w, /assets/CSL5c1vC-game_n_qwik_part2_main.webp 400w, /assets/wssyWlrC-game_n_qwik_part2_main.webp 600w, /assets/CajMSW2B-game_n_qwik_part2_main.webp 800w, /assets/Bmg8EZRn-game_n_qwik_part2_main.webp 1200w",I=1200,x=761,j={srcSet:T,width:I,height:x};function q(e,t,d,p){return l("img",{decoding:"async",loading:"lazy",...e},j,void 0,3,t)}const M=()=>(o(i(()=>s(()=>Promise.resolve().then(()=>E),void 0),"s_ec0xB0KRZs4")),o(i(()=>s(()=>Promise.resolve().then(()=>L),void 0),"s_jVdA4LjTaVY")),v(i(()=>s(()=>Promise.resolve().then(()=>A),void 0),"s_eb1lwacWQrA")),a(w,{type:"article",slide:!1,children:[a(h,{get article(){return{title:"Game-n-Qwik. Episode 02.",thumbnail:c(q,{class:"w-full h-full",...r("Game-n-Qwik. Episode 02.",1)}),author:"Vyacheslav Chub",authorImg:c(S,{...r("Game-n-Qwik. Episode 02.",0)}),position:"Full Stack Software Engineer",readingTime:"~11 min",date:"Wed Jul 12 2023 10:45:55 GMT+0000 (Coordinated Universal Time)"}},[n]:{article:n}},3,"3e_0"),l("div",null,{class:"article-body"},l("div",null,{class:"sect1"},[l("h2",null,{id:"_the_first_scratches"},"The First Scratches.",3,null),l("div",null,{class:"sectionbody"},[l("div",null,{class:"paragraph"},l("p",null,null,["I introduced you to the general Columns Game idea in the ",l("a",null,{href:"https://valor-software.com/articles/game-n-qwik-episode-01",target:"_blank",rel:"noopener"},"previous episode",3,null),". And now, itâs time to move forward. This episode will explain how to start the game implementation on ",l("a",null,{href:"https://qwik.builder.io",target:"_blank",rel:"noopener"},"Qwik",3,null),". The first steps will include the following points."],3,null),3,null),l("div",null,{class:"olist arabic"},l("ol",null,{class:"arabic"},[l("li",null,null,l("p",null,null,"Bootstrapping.",3,null),3,null),l("li",null,null,l("p",null,null,"The first steps in gameplay.",3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"But before, I want to speculate a bit regarding the Web implementation of an Arcade Game and focus on one strategic topic. First, we must understand what issues to consider to implement the game successfully. They are the following:",3,null),3,null),l("div",null,{class:"ulist"},l("ul",null,null,[l("li",null,null,l("p",null,null,"Library or Framework. In this case, we talk about Qwik, as I explained in Episode 01.",3,null),3,null),l("li",null,null,l("p",null,null,"We need to choose an approach for graphical objects drawing. Of course, we can use a pure HTML canvas-based approach. But letâs not reinvent the wheel; letâs wear it out.",3,null),3,null),l("li",null,null,l("p",null,null,"It is also essential to determine which CSS framework we will use. In my mind, pure CSS usage is also not a good idea for the reason explained in the previous point.",3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Itâs time to start our implementation with the points above covering.",3,null),3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_bootstrapping"},"Bootstrapping.",3,null),l("div",null,{class:"paragraph"},l("p",null,null,["I recommend ",l("a",null,{href:"https://qwik.builder.io/docs/getting-started",target:"_blank",rel:"noopener"},"Getting Started Qwikly",3,null)," before we start."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Please, run",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">npx npm create qwik@latest</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"and answer the following questions as:",3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,[l("mark",null,null,"Where would you like to create your new project?",3,null),l("br",null,null,null,3,null),"./qwik-columns",l("br",null,null,null,3,null),l("mark",null,null,"Select a starter",3,null),l("br",null,null,null,3,null),"Basic App",l("br",null,null,null,3,null),l("mark",null,null,"Would you like to install npm dependencies?",3,null),l("br",null,null,null,3,null),"Yes",l("br",null,null,null,3,null),l("mark",null,null,"Initialize a new git repository?",3,null),l("br",null,null,null,3,null),"Yes or No, itâs your choiceâ¦â",l("br",null,null,null,3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Congratulations! We just successfully started bootstrapping.",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">cd qwik-columns</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Letâs return to the points above regarding Graphical Drawing and CSS.",3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Before the first serious facing with ",l("a",null,{href:"https://d3js.org",target:"_blank",rel:"noopener"},"D3",3,null),", I thought this beautiful library was just about charts. But as far as I implemented different custom charts, I found this is a delusion. One of the main pros of D3 is its universality. In the following episodes, Iâll prove it! Together we will implement the game via D3!"],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Currently, I donât see any alternative to the ",l("a",null,{href:"https://d3js.org",target:"_blank",rel:"noopener"},"D3",3,null)," drawing approach because:"],3,null),3,null),l("div",null,{class:"olist arabic"},l("ol",null,{class:"arabic"},[l("li",null,null,l("p",null,null,"It has powerful shape-drawing tools and color management.",3,null),3,null),l("li",null,null,l("p",null,null,"D3 is about vector graphics; also, this library is animation-friendly.",3,null),3,null),l("li",null,null,l("p",null,null,"It allows associating (or binding) data to the graphical representation.",3,null),3,null),l("li",null,null,l("p",null,null,"It has a lot of patterns, like different, even tricky chart types.",3,null),3,null),l("li",null,null,l("p",null,null,"D3 is well-documented and has a vast community.",3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Letâs install D3 dependencies.",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">npm i d3 --save</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Also, we need to install expected typings",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">npm i @types/d3 --save-dev</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Letâs switch to CSS issue.",3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["The relationships between me and CSS are very pragmatic because Iâm a full-stack guy and always donât have much time for sophisticated dancing with CSS. Of course, I understand and respect the beauty of ",l("a",null,{href:"https://getbem.com/introduction",target:"_blank",rel:"noopener"},"BEM",3,null)," and ",l("a",null,{href:"https://www.arekibo.com/blog/popular-css-methodologies-for-scaling-web-projects",target:"_blank",rel:"noopener"},"some other methodologies",3,null),". But Iâm simultaneously thinking about architecture and design, the beauty of JS, TS, Go, Rust code, DB structure, etc. Moreover, some existing CSS-based implementations make me suffer and waste my time. A good example is ",l("a",null,{href:"https://chipperci.com/news/node-sass-node-gyp-nodejs-errors",target:"_blank",rel:"noopener"},"Node-sass and Node-gyp Errors",3,null),". Thatâs why I expect something powerful, easy, and lightweight. According to the ",l("a",null,{href:"https://www.webdesignerdepot.com/202
11/09/the-pros-and-cons-of-tailwind-css",target:"_blank",rel:"noopener"},"following points",3,null),", I think ",l("a",null,{href:"https://tailwindcss.com",target:"_blank",rel:"noopener"},"Tailwindcss",3,null)," is the best choice."],3,null),3,null),l("div",null,{class:"olist arabic"},l("ol",null,{class:"arabic"},[l("li",null,null,l("p",null,null,"Control Over Styling",3,null),3,null),l("li",null,null,l("p",null,null,"Faster CSS Styling Process",3,null),3,null),l("li",null,null,l("p",null,null,"Responsiveness and Security",3,null),3,null),l("li",null,null,l("p",null,null,"Additional Features. Tailwind CSS works in the front end of a website. For this reason, it is reasonable for developers to demand ultimate responsiveness. Well, Tailwind provides the ability to create responsive themes for your web applications and remove all unused CSS classes. With PurgeCSS, Tailwind helps you keep your final CSS as small as possible.",3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Of course, it has ",l("a",null,{href:"https://www.webdesignerdepot.com/2021/09/the-pros-and-cons-of-tailwind-css",target:"_blank",rel:"noopener"},"some cons",3,null),"."],3,null),3,null),l("div",null,{class:"olist arabic"},l("ol",null,{class:"arabic"},[l("li",null,null,l("p",null,null,"Styling and HTML are Mixed",3,null),3,null),l("li",null,null,l("p",null,null,"Lack of Important Components",3,null),3,null),l("li",null,null,l("p",null,null,"It Takes Time to Learn",3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Letâs analyze them. The first couple is only relevant when considering big or even enterprise projects. In that case, we could think about another framework. Regarding the third point, I agree only partially because Tailwind is well-documented, and you can also find many examples and valuable existing approaches. Our current project is not so large, and we can 100% use Tailwind which keeps our time and nervousness.",3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Fortunately, Qwik is super friendly with Tailwind!",3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Please, follow this ",l("a",null,{href:"https://qwik.builder.io/docs/integrations/tailwind",target:"_blank",rel:"noopener"},"documentation",3,null),"."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Letâs do it.",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">npm run qwik add tailwind</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,'Answer "Yes." Thatâs it. Feel free to use Tailwind in the project!',3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_the_first_steps_in_gameplay"},"The first steps in Gameplay.",3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Itâs time to think about our first steps regarding gameplay. I want to take my time with this and pass it through the following steps.",3,null),3,null),l("div",null,{class:"olist arabic"},l("ol",null,{class:"arabic"},[l("li",null,null,l("p",null,null,"Make a working canvas.",3,null),3,null),l("li",null,null,l("p",null,null,"Implement an elementary moving shape, say, a square.",3,null),3,null),l("li",null,null,l("p",null,null,"Make the shape above also movable via keyboard events.",3,null),3,null),l("li",null,null,l("p",null,null,"These steps will efficiently introduce you to the future tricky gameplay.",3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Create a new folder: ",l("mark",null,null,"src/components/game-play",3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Put ",l("mark",null,null,"utils.ts",3,null)," there."],3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">import type { Signal } from "@builder.io/qwik"; 2import type { MainStore } from "./game"; 3 4export function setSvgDimension( 5 svgRef: Signal<Element | undefined>, 6 store: MainStore 7) { 8 if (svgRef?.value) { 9 const { width, height } = svgRef.value.getBoundingClientRect(); 10 11 store.width = width; 12 store.height = height; 13 } 14}</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["The main goal of ",l("mark",null,null,"setSvgDimensionis",3,null)," to set keep width and height of a component in the ",l("a",null,{href:"https://qwik.builder.io/tutorial/introduction/store/",target:"_blank",rel:"noopener"},"Qwik store",3,null),". The component is represented by svgRef as a ",l("a",null,{href:"https://qwik.builder.io/docs/components/state/",target:"_blank",rel:"noopener"},"Qwik Signal",3,null),". Please, look at a couple of links above if Qwik is something new to you."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Put the following content into ",l("mark",null,null,"src/routes/index.tsx",3,null)],3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">import { component$ } from "@builder.io/qwik"; 15import Game from "../components/game-play/game";
16 17export default component$(() => { 18 return <Game />; 19});</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Remove ",l("mark",null,null,"src/components/starter",3,null)," folder. Also, remove all files except ",l("mark",null,null,"src/routes/index.tsx",3,null)," from ",l("mark",null,null,"src/routes/",3,null),". And finally, put ",l("mark",null,null,"game.tsx",3,null)," file into ",l("mark",null,null,"src/components/game-play",3,null),"."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,l("mark",null,null,"game.tsx",3,null),3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">import type { Signal } from "@builder.io/qwik"; 20import { useVisibleTask$ } from "@builder.io/qwik"; 21import { 22 component$, 23 useStore, 24 useSignal, 25 useOnDocument, 26 useOnWindow, 27 $, 28} from "@builder.io/qwik"; 29import * as d3 from "d3"; 30import { setSvgDimension } from "./utils"; 31 32export function render( 33 svgRef: Signal<Element | undefined>, 34 width: number, 35 height: number, 36 x: number, 37 y: number 38) { 39 if (!svgRef.value) { 40 return; 41 } 42 43 const svg = d3.select(svgRef.value); 44 svg.selectAll("*").remove(); 45 svg 46 .append("svg") 47 .attr("width", width) 48 .attr("height", height) 49 .append("g") 50 .attr("transform", "translate(0,0)"); 51 52 svg 53 .append("g") 54 .append("rect") 55 .attr("x", 0) 56 .attr("width", width) 57 .attr("y", 0) 58 .attr("height", height) 59 // @ts-ignore 60 .attr("fill", () => d3.color("#ffffff")); 61 62 const data = [{ x, y }]; 63 64 svg 65 .selectAll() 66 .data(data) 67 .enter() 68 .append("g") 69 .append("rect") 70 .attr("x", (d) => d.x) 71 .attr("width", 15) 72 .attr("y", (d) => d.y) 73 .attr("height", 15) 74 // @ts-ignore 75 .attr("fill", () => d3.color("#ff0000")); 76} 77 78export interface MainStore { 79 width: number; 80 height: number; 81 horPos: number; 82 vertPos: number; 83} 84 85export default component$(() => { 86 const store = useStore<MainStore>({ 87 width: 0, 88 height: 0, 89 horPos: 200, 90 vertPos: 0, 91 }); 92 const containerRef = useSignal<Element>(); 93 const svgRef = useSignal<Element>(); 94 95 useOnWindow( 96 "resize", 97 $(() => { 98 setSvgDimension(containerRef, store); 99 }) 100 ); 101 102 useOnDocument( 103 "keypress", 104 $((event) => { 105 const keyEvent = event as KeyboardEvent; 106 if (keyEvent.code === "KeyA") { 107 store.horPos -= 10; 108 } else if (keyEvent.code === "KeyD") { 109 store.horPos += 10; 110 } 111 }) 112 ); 113 114 useVisibleTask$(({ cleanup }: { cleanup: Function }) => { 115 setSvgDimension(containerRef, store); 116 const intervalId = setInterval(() => { 117 store.vertPos += 10; 118 render(svgRef, store.width, store.height, store.horPos, store.vertPos); 119 }, 700); 120 cleanup(() => clearInterval(intervalId)); 121 }); 122 123 return ( 124 <div class="flex justify-center w-screen h-screen pt-5" ref={containerRef}> 125 <svg 126 class="game-area" 127 width={store.width} 128 height={store.height} 129 ref={svgRef} 130 /> 131 </div> 132 ); 133});</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Itâs time to run the solution: ",l("mark",null,null,"npm start",3,null),"."],3,null),3,null),l("div",null,{class:"imageblock small-img"},l("div",null,{class:"content"},l("img",null,{title:"Game-n-Qwik. Episode 02., photo 2 - valor-software.com",src:"/assets/articles/game-n-qwik-episode-02/img1.gif",alt:"Game-n-Qwik. Episode 02., photo 2 - Valor Software"},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,'As we can see here, there is a moving square. You can move it left via the "A" key and right via "D."',3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["If you want to dig into this code immediately, please use ",l("a",null,{href:"https://github.com/buchslava/qwik-columns/tree/step-3",target:"_blank",rel:"noopener"}
133,"this source",3,null),"."],3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_the_html_part"},"The HTML part",3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-html" data-lang="html"><div class="flex justify-center w-screen h-screen pt-5" ref={containerRef}> 134 <svg 135 class="game-area" 136 width={store.width} 137 height={store.height} 138 ref={svgRef} 139 /> 140</div></code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"We use SVG as a game board container. It will be represented as a Qwik Signal.",3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_the_signals"},"The Signals",3,null),l("div",null,{class:"quoteblock"},l("blockquote",null,null,[l("div",null,{class:"paragraph"},l("p",null,null,["Use ",l("mark",null,null,"useSignal()",3,null)," to create a reactive signal (a form of state). The ",l("mark",null,null,"useSignal()",3,null)," takes an initial value and returns a reactive signal."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["The reactive signal returned by ",l("mark",null,null,"useSignal()",3,null)," consists of an object with a single property .value. If you change the value property of the signal, any component that depends on it will be updated automatically."],3,null),3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["We use ",l("mark",null,null,"containerRef",3,null)," as a data associated with the root element. BTW, pay attention to the Tailwind-based 'class.' The aim of ",l("mark",null,null,"containerRef",3,null)," is to keep the dimension of the screen."],3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">const containerRef = useSignal<Element>(); 141const svgRef = useSignal<Element>();</code>`},null,3,null),3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_the_store"},"The Store",3,null),l("div",null,{class:"paragraph"},l("p",null,null,"The heart of the component is a store.",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">export interface MainStore { 142 width: number; 143 height: number; 144 horPos: number; 145 vertPos: number; 146}</code>`},null,3,null),3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">const store = useStore<MainStore>({ 147 width: 0, 148 height: 0, 149 horPos: 200, 150 vertPos: 0, 151});</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"We keep the following data:",3,null),3,null),l("div",null,{class:"ulist"},l("ul",null,null,[l("li",null,null,l("p",null,null,"Width and height of the component (root component dimension equals to the rootâs)",3,null),3,null),l("li",null,null,l("p",null,null,"Horizontal and vertical positions of the square",3,null),3,null)],3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_initializingresuming"},"Initializing/resuming",3,null),l("div",null,{class:"paragraph"},l("p",null,null,[l("mark",null,null,"useVisibleTask$",3,null)," hook is very important in Qwik because"],3,null),3,null),l("div",null,{class:"quoteblock"},l("blockquote",null,null,l("div",null,{class:"paragraph"},l("p",null,null,["Use ",l("a",null,{href:"https://qwik.builder.io/tutorial/hooks/use-visible-task/",target:"_blank",rel:"noopener"},"useVisibleTask$()",3,null)," to execute code after the component is resumed. This is useful for setting up timers or streams on the client when the application is resumed."],3,null),3,null),3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">useVisibleTask$(({ cleanup }: { cleanup: Function }) => { 152 setSvgDimension(containerRef, store); 153 const intervalId = setInterval(() => { 154 store.vertPos += 10; 155 render(svgRef, store.width, store.height, store.horPos, store.vertPos); 156 }, 700); 157 cleanup(() => clearInterval(intervalId)); 158});</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"There are two main activities above.",3,null),3,null),l("div",null,{class:"olist arabic"},l("ol",null,{class:"arabic"},[l("li",null,null,l("p",null,null,["Set the root component/board dimension: ",l("mark",null,null,"setSvgDimension(containerRef, store)",3,null),";"],3,null),3,null),l("li",null,null,l("p",null,null,["Provide a main loop of the game via ",l("mark",null,null,"setInterval",3,null),"."],3,null),3,null)],3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_the_main_loop"},"The main loop",3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Letâs dig into the main loop. Moving down is represented by ",l("mark",null,null,"store.vertPos += 10;",3,null),". We just adding 10 pixels every 700 millisecond."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"After, we should render the board and the square.",3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_the_render"},"The render",3,null),l("div",null,{class:"paragraph"},l("p",null,null,[l("mark",null,null,"render",3,null)," function literally does the following things."],3,null),3,null),l("div",null,{class:"ulist"},l("ul",null,null,l("li",null,null,l("p",null,null,["It takes the SVG-based component representation ",l("mark",null,null,"svgRef.value",3,null)," and binds it with ",l("mark",null,null,"svg",3,null)," variable via ",l("mark",null,null,"d3.select",3,null)," method. Clears all previous stuff in the SVG if it does exist."],3,null),3,null),3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">const svg = d3.select(svgRef.value); 159svg.selectAll("*").remove();</code>`},null,3,null),3,null),3,null),l("div",null,{class:"ulist"},l("ul",null,null,l("li",null,null,l("p",null,null,["Draws a white rectangle due to the screen dimension. BTW, the ",l("a",null,{href:"https://stackoverflow.com/questions/42568992/how-to-draw-a-rectangle-in-d3-js-with-only-2-coordinates",target:"_blank",rel:"noopener"},"following link",3,null)," will be useful."],3,null),3,null),3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-css" data-lang="css">svg 160 .append("svg") 161 .attr("width", width) 162 .attr("height", height) 163 .append("g") 164 .attr("transform", "translate(0,0)"); 165 166svg 167 .append("g") 168 .append("rect") 169 .attr("x", 0) 170 .attr("width", width) 171 .attr("y", 0) 172 .attr("height", height) 173 // @ts-ignore 174 .attr("fill", () => d3.color("#ffffff"));</code>`},null,3,null),3,null),3,null),l("div",null,{class:"ulist"},l("ul",null,null,l("li",null,null,l("p",null,null,"Associate the SVG-based component with x and y (just one element) and draw it.",3,null),3,null),3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">const data = [{ x, y }]; 175 176svg 177 .selectAll() 178 .data(data) 179 .enter() 180 .append("g") 181 .append("rect") 182 .attr("x", (d) => d.x) 183 .attr("width", 15) 184 .attr("y", (d) => d.y) 185 .attr("height", 15) 186 // red 187 .attr("fill", () => d3.color("#ff0000"));</code>`},null,3,null),3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_recalculate_the_board_dimension_and_keyboard_processing"},"Recalculate the board dimension and keyboard processing",3,null),l("div",null,{class:"quoteblock"},l("blockquote",null,null,l("div",null,{class:"paragraph"},l("p",null,null,["Use ",l("mark",null,null,"useOn()",3,null)," / ",l("mark",null,null,"useOnDocument()",3,null)," / ",l("mark",null,null,"useOnWindow()",3,null)," to programmatically set up listeners on host elements. This is useful when you are creating custom APIs and donât have access to place these events in the JSX or if the events are not known ahead of time, such as if they are created based on component props."],3,null),3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"The following code allows us to resize the component during the window resizing.",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">useOnWindow( 188 "resize", 189 $(() => { 190 setSvgDimension(containerRef, store); 191 }) 192);</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,'The following code allows us to process keyboard events. In this example, a user moves the square left when the "A" key has been pressed and right if the "D" key has been pressed.',3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-js" data-lang="js">useOnDocument( 193 "keypress", 194 $((event) => {
195 const keyEvent = event as KeyboardEvent; 196 if (keyEvent.code === "KeyA") { 197 store.horPos -= 10; 198 } else if (keyEvent.code === "KeyD") { 199 store.horPos += 10; 200 } 201 }) 202);</code>`},null,3,null),3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_build_process"},"Build process",3,null),l("div",null,{class:"paragraph"},l("p",null,null,"Itâs time to build the solution.",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">npm run build</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"It seems we passed this step successfully. But please pay attention to the text at the bottom:",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:`<code class="language-bash" data-lang="bash">Missing an integration 203 204ã» Use npm run qwik add to add an integration 205ã» Use npm run preview to preview the build</code>`},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["As a result, you donât see ",l("mark",null,null,"index.html",3,null)," in the ",l("mark",null,null,"dist",3,null)," folder. Letâs fix this issue."],3,
205null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,"If you want to make this solution web-friendly, please run:",3,null),3,null),l("div",null,{class:"listingblock"},l("div",null,{class:"content"},l("pre",null,{class:"highlight",dangerouslySetInnerHTML:'<code class="language-bash" data-lang="bash">npm run qwik add</code>'},null,3,null),3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,[l("mark",null,null,"What integration would you like to add?",3,null),l("br",null,null,null,3,null),"Adapter: Static site (.html files)",l("br",null,null,null,3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,[l("mark",null,null,"Ready to apply the static updates to your app?",3,null),l("br",null,null,null,3,null),"Yes looks good, finish update!",l("br",null,null,null,3,null)],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Letâs build the solution againâ¦â And now we should see the expected ",l("mark",null,null,"index.html",3,null),"."],3,null),3,null),l("div",null,{class:"paragraph"},l("p",null,null,["Please, read ",l("a",null,{href:"https://qwik.builder.io/docs/deployments/",target:"_blank",rel:"noopener"},"Qwik Deployments",3,null)," if you need to learn more about Qwik providers."],3,null),3,null)],3,null),l("div",null,{class:"sect2"},[l("h3",null,{id:"_whats_next"},"Whatâs next?",3,null),l("div",null,{class:"paragraph"},l("p",null,null,["I hope this episode was useful and informative. Feel free to read and run ",l("a",null,{href:"https://github.com/buchslava/qwik-columns/tree/step-3",target:"_blank",rel:"noopener"},"this solution",3,null),". But it is just preparation before the actual gameplay implementation. The next episode will disclose all the main secrets about the game! See you!"],3,null),3,null)],3,null)],3,null)],3,null),3,null),l("div",null,null,[l("h2",null,null," More Articles ",3,null),l("div",null,{class:"more-articles"},[l("div",null,{class:"more-item"},a(u,{href:"/articles/the-secrets-of-efficient-cv-analyzing-the-ee-pattern-tips-and-tricks",children:[l("img",null,{src:"/assets/articles/the-secrets-of-efficient-cv-analyzing-the-ee-pattern-tips-and-tricks/img.png",alt:"Background"},null,3,null),l("h4",null,null,"The secrets of efficient CV analyzing. The E-pattern. Tips & Tricks",3,null)],[n]:{href:n}},3,"3e_1"),1,null),l("div",null,{class:"more-item"},a(u,{href:"/articles/interview-transcription-using-whisperx-model-part-1",children:[l("img",null,{src:"/assets/articles/interview-transcription-using-whisperx-model-part-1/img.png",alt:"Background"},null,3,null),l("h4",null,null,"Interview transcription using WhisperX model, Part 1.",3,null)],[n]:{href:n}},3,"3e_2"),1,null),l("div",null,{class:"more-item"},a(u,{href:"/articles/tauri-crud-boilerplate",children:[l("img",null,{src:"/assets/articles/tauri-crud-boilerplate/tauri_crud_boilerplate_main.png",alt:"Background"},null,3,null),l("h4",null,null,"Tauri CRUD Boilerplate",3,null)],[n]:{href:n}},3,"3e_3"),1,null)],1,null)],1,null)],[n]:{type:n,slide:n}},1,"3e_4")),B=Object.freeze(Object.defineProperty({__proto__:null,s_agCZcWnIIhA:M},Symbol.toStringTag,{value:"Module"})),P=g,L=Object.freeze(Object.defineProperty({__proto__:null,s_jVdA4LjTaVY:P},Symbol.toStringTag,{value:"Module"})),R=()=>{const e=document.createElement("script");e.src="/scripts/prism.js",Array.from(document.body.children).map(t=>t.src).join("").includes(e.src)||document.body.appendChild(e)},A=Object.freeze(Object.defineProperty({__proto__:null,_hW:f,s_eb1lwacWQrA:R},Symbol.toStringTag,{value:"Module"})),C=m,E=Object.freeze(Object.defineProperty({__proto__:null,s_ec0xB0KRZs4:C},Symbol.toStringTag,{value:"Module"}));export{R as a,C as b,B as i,P as s,M as s_agCZcWnIIhA};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.