PageSourceSearch

https://valor-software.com/build/q-B-vSid1C.js

js valor-software.com collected 2026-09-25 14:03:34 UTC 32,483 bytes, 205 lines download raw bytes

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&lt;Element | undefined&gt;,
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$(() =&gt; {
18  return &lt;Game /&gt;;
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&lt;Element | undefined&gt;,
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", () =&gt; 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) =&gt; d.x)
71    .attr("width", 15)
72    .attr("y", (d) =&gt; d.y)
73    .attr("height", 15)
74    // @ts-ignore
75    .attr("fill", () =&gt; 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$(() =&gt; {
86  const store = useStore&lt;MainStore&gt;({
87    width: 0,
88    height: 0,
89    horPos: 200,
90    vertPos: 0,
91  });
92  const containerRef = useSignal&lt;Element&gt;();
93  const svgRef = useSignal&lt;Element&gt;();
94
95  useOnWindow(
96    "resize",
97    $(() =&gt; {
98      setSvgDimension(containerRef, store);
99    })
100  );
101
102  useOnDocument(
103    "keypress",
104    $((event) =&gt; {
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 }) =&gt; {
115    setSvgDimension(containerRef, store);
116    const intervalId = setInterval(() =&gt; {
117      store.vertPos += 10;
118      render(svgRef, store.width, store.height, store.horPos, store.vertPos);
119    }, 700);
120    cleanup(() =&gt; clearInterval(intervalId));
121  });
122
123  return (
124    &lt;div class="flex justify-center w-screen h-screen pt-5" ref={containerRef}&gt;
125      &lt;svg
126        class="game-area"
127        width={store.width}
128        height={store.height}
129        ref={svgRef}
130      /&gt;
131    &lt;/div&gt;
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">&lt;div class="flex justify-center w-screen h-screen pt-5" ref={containerRef}&gt;
134  &lt;svg
135    class="game-area"
136    width={store.width}
137    height={store.height}
138    ref={svgRef}
139  /&gt;
140&lt;/div&gt;</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&lt;Element&gt;();
141const svgRef = useSignal&lt;Element&gt;();</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&lt;MainStore&gt;({
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 }) =&gt; {
152  setSvgDimension(containerRef, store);
153  const intervalId = setInterval(() =&gt; {
154    store.vertPos += 10;
155    render(svgRef, store.width, store.height, store.horPos, store.vertPos);
156  }, 700);
157  cleanup(() =&gt; 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", () =&gt; 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) =&gt; d.x)
183  .attr("width", 15)
184  .attr("y", (d) =&gt; d.y)
185  .attr("height", 15)
186  // red
187  .attr("fill", () =&gt; 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  $(() =&gt; {
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) =&gt; {
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.