लाइट-एलिमेंट की मदद से ब्रिक व्यूअर बनाएं

1. परिचय

वेब कॉम्पोनेंट

वेब कॉम्पोनेंट, उन वेब स्टैंडर्ड का कलेक्शन हैं जिनकी मदद से डेवलपर, कस्टम एलिमेंट वाले एचटीएमएल का इस्तेमाल कर सकते हैं. इस कोडलैब में, आपको <brick-viewer> एलिमेंट तय करना होगा. इससे ईंट के मॉडल दिखाए जा सकेंगे!

लाइट-एलिमेंट

अपने कस्टम एलिमेंट <brick-viewer> को तय करने में मदद पाने के लिए, हम lit-element का इस्तेमाल करेंगे. lit-element एक लाइटवेट बेस क्लास है, जो वेब कॉम्पोनेंट स्टैंडर्ड में कुछ सिंटैक्टिक शुगर जोड़ती है. इससे हमारे लिए, कस्टम एलिमेंट का इस्तेमाल करना आसान हो जाएगा.

शुरू करें

हम ऑनलाइन Stackblitz प्लैटफ़ॉर्म पर कोडिंग करेंगे. इसलिए, इस लिंक को नई विंडो में खोलें:

stackblitz.com/edit/brick-viewer

आइए, शुरू करें!

2. कस्टम एलिमेंट तय करें

क्लास की परिभाषा

कस्टम एलिमेंट तय करने के लिए, LitElement को बड़ा करने वाली क्लास बनाएं और उसे @customElement से सजाएं. @customElement का तर्क कस्टम एलिमेंट का नाम होगा.

brick-viewer.ts में, यह डालें:

@customElement('brick-viewer')
export class BrickViewer extends LitElement {
}

अब <brick-viewer></brick-viewer> एलिमेंट, एचटीएमएल में इस्तेमाल के लिए तैयार है. हालांकि, अगर आपने इसे आज़माया है, तो कुछ भी रेंडर नहीं होगा. चलिए, इसे ठीक करते हैं।

रेंडर करने का तरीका

कॉम्पोनेंट के व्यू को लागू करने के लिए, 'रेंडर' नाम का कोई तरीका तय करें. इस तरीके से, html फ़ंक्शन के साथ टैग किया गया टेंप्लेट मिलना चाहिए. टैग किए गए टेंप्लेट में अपनी पसंद का कोई भी एचटीएमएल डालें. यह <brick-viewer> का इस्तेमाल करने पर रेंडर होगा.

render तरीका जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`<div>Brick viewer</div>`;
  }
}

3. LDraw फ़ाइल की जानकारी देना

प्रॉपर्टी तय करना

अगर <brick-viewer> का उपयोगकर्ता यह तय कर सके कि एट्रिब्यूट का इस्तेमाल करके ब्रिक का कौनसा मॉडल दिखाना है, तो बहुत अच्छा होगा, जैसे कि:

<brick-viewer src="path/to/model.ldraw"></brick-viewer>

हम एक एचटीएमएल एलिमेंट बना रहे हैं. इसलिए, हम डिक्लेरेटिव एपीआई का फ़ायदा ले सकते हैं और <img> या <video> टैग की तरह ही सोर्स एट्रिब्यूट तय कर सकते हैं. लिट-एलिमेंट की मदद से, यह @property की मदद से क्लास की प्रॉपर्टी को सजाने जितना आसान है. type विकल्प से आप यह तय कर सकते हैं कि lit-element, एचटीएमएल एट्रिब्यूट के तौर पर इस्तेमाल करने के लिए, प्रॉपर्टी को कैसे पार्स करता है.

src प्रॉपर्टी और एट्रिब्यूट तय करें:

export class BrickViewer extends LitElement {
  @property({type: String})
  src: string|null = null;
}

<brick-viewer> में अब src एट्रिब्यूट है, जिसे हम एचटीएमएल में सेट कर सकते हैं! lit-element की मदद से, इसकी वैल्यू को हमारी BrickViewer क्लास में पहले से ही पढ़ा जा सकता है.

वैल्यू दिखाई जा रही हैं

हम src एट्रिब्यूट की वैल्यू को रेंडर करने के तरीके के टेंप्लेट लिटरल में इस्तेमाल करके दिखा सकते हैं. ${value} सिंटैक्स का इस्तेमाल करके, टेंप्लेट लिटरल में वैल्यू डालें.

export class BrickViewer extends LitElement {
  render() {
    return html`<div>Brick model: ${this.src}</div>`;
  }
}

अब, हमें विंडो में <brick-viewer> एलिमेंट में src एट्रिब्यूट की वैल्यू दिख रही है. इसे आज़माएं: अपने ब्राउज़र के डेवलपर टूल खोलें और src एट्रिब्यूट को मैन्युअल तरीके से बदलें. आइए, इसे आज़माएं...

...क्या आपको पता है कि एलिमेंट में टेक्स्ट अपने-आप अपडेट हो जाता है? lit-element, @property से सजाए गए क्लास प्रॉपर्टी को देखता है और आपके लिए व्यू को फिर से रेंडर करता है! lit-element, ज़्यादातर काम करता है, ताकि आपको परेशान न होना पड़े.

4. Three.js की मदद से सीन सेट करना

लाइट, कैमरा, रेंडर!

हमारे कस्टम एलिमेंट, हमारे 3D ब्रिक मॉडल को रेंडर करने के लिएthree.js का इस्तेमाल करेंगे. कुछ ऐसी चीज़ें हैं जिन्हें हम <brick-viewer> एलिमेंट के हर इंस्टेंस के लिए, सिर्फ़ एक बार करना चाहते हैं, जैसे कि Three.js सीन, कैमरा, और लाइटिंग सेट अप करना. हम इन्हें कंस्ट्रक्टर की BrickViewer क्लास में जोड़ेंगे. हम कुछ ऑब्जेक्ट को क्लास प्रॉपर्टी के तौर पर रखेंगे, ताकि हम बाद में उनका इस्तेमाल कर सकें: कैमरा, सीन, कंट्रोल, और रेंडरर.

तीन.js सीन सेटअप में जोड़ें:

export class BrickViewer extends LitElement {

  private _camera: THREE.PerspectiveCamera;
  private _scene: THREE.Scene;
  private _controls: OrbitControls;
  private _renderer: THREE.WebGLRenderer;

  constructor() {
    super();

    this._camera = new THREE.PerspectiveCamera(45, this.clientWidth/this.clientHeight, 1, 10000);
    this._camera.position.set(150, 200, 250);

    this._scene = new THREE.Scene();
    this._scene.background = new THREE.Color(0xdeebed);

    const ambientLight = new THREE.AmbientLight(0xdeebed, 0.4);
    this._scene.add( ambientLight );

    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(-1000, 1200, 1500);
    this._scene.add(directionalLight);

    this._renderer = new THREE.WebGLRenderer({antialias: true});
    this._renderer.setPixelRatio(window.devicePixelRatio);
    this._renderer.setSize(this.offsetWidth, this.offsetHeight);

    this._controls = new OrbitControls(this._camera, this._renderer.domElement);
    this._controls.addEventListener("change", () =>
      requestAnimationFrame(this._animate)
    );

    this._animate();

    const resizeObserver = new ResizeObserver(this._onResize);
    resizeObserver.observe(this);
  }

  private _onResize = (entries: ResizeObserverEntry[]) => {
    const { width, height } = entries[0].contentRect;
    this._renderer.setSize(width, height);
    this._camera.aspect = width / height;
    this._camera.updateProjectionMatrix();
    requestAnimationFrame(this._animate);
  };

  private _animate = () => {
    this._renderer.render(this._scene, this._camera);
  };
}

WebGLRenderer ऑब्जेक्ट, एक ऐसा DOM एलिमेंट उपलब्ध कराता है जो रेंडर किए गए three.js सीन को दिखाता है. इसे domElement प्रॉपर्टी से ऐक्सेस किया जाता है. हम ${value} सिंटैक्स का इस्तेमाल करके, इस वैल्यू को रेंडर टेंप्लेट लिटरल में इंटरपोलेट कर सकते हैं.

टेंप्लेट में मौजूद src मैसेज को हटाएं और रेंडरर का डीओएम एलिमेंट डालें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      ${this._renderer.domElement}
    `;
  }
}

रेंडरर के डोम एलिमेंट को पूरी तरह से दिखाने के लिए, हमें <brick-viewer> एलिमेंट को भी display: block पर सेट करना होगा. हम styles नाम की स्टैटिक प्रॉपर्टी में स्टाइल दे सकते हैं, जिसे css टेंप्लेट लिटरल पर सेट किया गया है.

क्लास में यह स्टाइल जोड़ें:

export class BrickViewer extends LitElement {
  static styles = css`
    /* The :host selector styles the brick-viewer itself! */
    :host {
      display: block;
    }
  `;
}

अब <brick-viewer> में, रेंडर किया गया segment.js सीन दिखाया जा रहा है:

ब्रिक व्यूअर एलिमेंट में रेंडर किया गया, लेकिन खाली सीन दिख रहा है.

हालांकि, यह खाली है. चलिए, इसे एक मॉडल देते हैं.

ईंट लोडर

हम पहले से तय की गई src प्रॉपर्टी को LDrawLoader में पास करेंगे. यह प्रॉपर्टी, three.js के साथ शिप की जाती है.

LDraw फ़ाइलें किसी ब्रिक मॉडल को बिल्डिंग के अलग-अलग चरणों में अलग करने में मदद कर सकती हैं. LDrawLoader API की मदद से, कदमों की कुल संख्या और ब्रिक दिखाने की हर सुविधा ऐक्सेस की जा सकती है.

इन प्रॉपर्टी, _loadModel के नए तरीके, और कंस्ट्रक्टर की नई लाइन को कॉपी करें:

@customElement('brick-viewer')
export class BrickViewer extends LitElement {
  private _loader = new LDrawLoader();
  private _model: any;
  private _numConstructionSteps?: number;
  step?: number;

  constructor() {
    // ...
    // Add this line right before this._animate();
    (this._loader as any).separateObjects = true;
    this._animate();
  }

  private _loadModel() {
    if (this.src === null) {
      return;
    }
    this._loader
        .setPath('')
        // Using our src property!
        .load(this.src, (newModel) => {

          if (this._model !== undefined) {
            this._scene.remove(this._model);
            this._model = undefined;
          }

          this._model = newModel;

          // Convert from LDraw coordinates: rotate 180 degrees around OX
          this._model.rotation.x = Math.PI;
          this._scene.add(this._model);

          this._numConstructionSteps = this._model.userData.numConstructionSteps;
          this.step = this._numConstructionSteps!;

          const bbox = new THREE.Box3().setFromObject(this._model);
          this._controls.target.copy(bbox.getCenter(new THREE.Vector3()));
          this._controls.update();
          this._controls.saveState();
        });
  }
}

_loadModel को कब कॉल करना है? src एट्रिब्यूट के बदलने पर, इसे हर बार लागू करना होगा. src प्रॉपर्टी को @property से डेकोर करने का मतलब है कि हमने इस प्रॉपर्टी को लिट-एलिमेंट के अपडेट होने की लाइफ़साइकल में शामिल किया है. जब भी इनमें से किसी एक प्रॉपर्टी की वैल्यू बदलती है, तो कई तरीके लागू होते हैं. इन तरीकों से प्रॉपर्टी की नई और पुरानी वैल्यू को ऐक्सेस किया जा सकता है. जिस लाइफ़साइकल मैथड में हमारी दिलचस्पी है उसे update कहा जाता है. update तरीके में PropertyValues आर्ग्युमेंट इस्तेमाल किया जाता है. इसमें, हाल ही में बदली गई सभी प्रॉपर्टी की जानकारी होती है. _loadModel को कॉल करने के लिए यह बिलकुल सही जगह है.

update वाला तरीका जोड़ें:

export class BrickViewer extends LitElement {
  update(changedProperties: PropertyValues) {
    if (changedProperties.has('src')) {
      this._loadModel();
    }
    super.update(changedProperties);
  }
}

हमारा <brick-viewer> एलिमेंट, अब src एट्रिब्यूट की मदद से तय की गई ब्रिक फ़ाइल दिखा सकता है.

ब्रिक व्यूअर एलिमेंट की इमेज, जिसमें कार का मॉडल दिखाया गया है.

5. कुछ मॉडल दिखाना

अब, चलिए हम कॉन्फ़िगरेशन के लिए, मौजूदा कन्स्ट्रक्शन चरण को सेट अप करते हैं. हमें <brick-viewer step="5"></brick-viewer> के बारे में बताना है. हमें पता चलेगा कि पांचवें चरण पर ब्रिक मॉडल कैसा दिखता है. ऐसा करने के लिए, step प्रॉपर्टी को @property से डेकोरेट करके, उसे निगरानी वाली प्रॉपर्टी बनाते हैं.

step प्रॉपर्टी को सजाएं:

export class BrickViewer extends LitElement {
  @property({type: Number})
  step?: number;
}

अब हम एक हेल्पर तरीका जोड़ेंगे, जिससे सिर्फ़ मौजूदा बिल्ड चरण तक के ब्रिक दिखेंगे. हम अपडेट करने के तरीके में हेल्पर को कॉल करेंगे, ताकि step प्रॉपर्टी में बदलाव होने पर, यह हर बार चल सके.

update वाला तरीका अपडेट करें और _updateBricksVisibility का नया तरीका जोड़ें:

export class BrickViewer extends LitElement {
  update(changedProperties: PropertyValues) {
    if (changedProperties.has('src')) {
      this._loadModel();
    }
    if (changedProperties.has('step')) {
      this._updateBricksVisibility();
    }
    super.update(changedProperties);
  }

  private _updateBricksVisibility() {
    this._model && this._model.traverse((c: any) => {
      if (c.isGroup && this.step) {
        c.visible = c.userData.constructionStep <= this.step;
      }
    });
    requestAnimationFrame(this._animate);
  }
}

ठीक है, अब अपने ब्राउज़र के devtools खोलें और <brick-viewer> एलिमेंट की जांच करें. उसमें step एट्रिब्यूट जोड़ें, जैसे:

ब्रिक व्यूअर एलिमेंट का एचटीएमएल कोड, जिसमें चरण एट्रिब्यूट 10 पर सेट किया गया है.

देखें कि रेंडर किए गए मॉडल का क्या होता है! हम step एट्रिब्यूट का इस्तेमाल करके, यह तय कर सकते हैं कि मॉडल का कितना हिस्सा दिखाया जाए. यहां बताया गया है कि जब step एट्रिब्यूट को "10" पर सेट किया जाता है, तो यह कैसा दिखना चाहिए:

ईंट का ऐसा मॉडल जिसे बनाने के लिए सिर्फ़ 10 चरण हैं.

6. ब्रिक सेट नेविगेशन

mwc-icon-button

हमारे <brick-viewer> के असली उपयोगकर्ता को भी यूज़र इंटरफ़ेस (यूआई) की मदद से, बिल्ड करने के चरणों को नेविगेट करने की सुविधा मिलनी चाहिए. अगले चरण, पिछले चरण, और पहले चरण पर जाने के लिए बटन जोड़ें. हम इसे आसान बनाने के लिए, Material Design के बटन वेब कॉम्पोनेंट का इस्तेमाल करेंगे. @material/mwc-icon-button को पहले ही इंपोर्ट कर लिया गया है, इसलिए हम इसे <mwc-icon-button></mwc-icon-button> में छोड़ सकते हैं. हम आइकॉन एट्रिब्यूट के साथ इस्तेमाल करने के लिए, पसंदीदा आइकॉन तय कर सकते हैं, जैसे कि: <mwc-icon-button icon="thumb_up"></mwc-icon-button>. सभी आइकॉन यहां देखे जा सकते हैं: material.io/resources/icons.

अब रेंडर करने के तरीके में कुछ आइकॉन बटन जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      ${this._renderer.domElement}
      <div id="controls">
        <mwc-icon-button icon="replay"></mwc-icon-button>
        <mwc-icon-button icon="navigate_before"></mwc-icon-button>
        <mwc-icon-button icon="navigate_next"></mwc-icon-button>
      </div>
    `;
  }
}

वेब कॉम्पोनेंट की मदद से, हमारे पेज पर मटीरियल डिज़ाइन का इस्तेमाल करना बेहद आसान है!

इवेंट बाइंडिंग

इन बटन से हमें कुछ काम करना चाहिए. "जवाब दें" बटन को कंस्ट्रक्शन के चरण को रीसेट करके एक पर सेट करना चाहिए. "नेविगेट_before" बटन से कंस्ट्रक्शन के चरण को कम करना चाहिए और "nav_next" बटन से इसे बढ़ाना चाहिए. lit-element टूल, इवेंट बाइंडिंग के साथ इस सुविधा को जोड़ना आसान बनाता है. अपने एचटीएमएल टेंप्लेट की लिटरल वैल्यू में, सिंटैक्स @eventname=${eventHandler} का इस्तेमाल एलिमेंट एट्रिब्यूट के तौर पर करें. eventHandler अब तब चलेगा, जब उस एलिमेंट पर eventname इवेंट का पता चलेगा! उदाहरण के लिए, आइए अपने तीन आइकॉन बटन में क्लिक इवेंट हैंडलर जोड़ें:

export class BrickViewer extends LitElement {
  private _restart() {
    this.step! = 1;
  }

  private _stepBack() {
    this.step! -= 1;
  }

  private _stepForward() {
    this.step! += 1;
  }

  render() {
    return html`
      ${this._renderer.domElement}
      <div id="controls">
        <mwc-icon-button @click=${this._restart} icon="replay"></mwc-icon-button>
        <mwc-icon-button @click=${this._stepBack} icon="navigate_before"></mwc-icon-button>
        <mwc-icon-button @click=${this._stepForward} icon="navigate_next"></mwc-icon-button>
      </div>
    `;
  }
}

अब बटन पर क्लिक करके देखें. बहुत बढ़िया!

स्टाइल

बटन काम करते हैं, लेकिन वे अच्छे नहीं लगते. ये सभी सबसे नीचे मौजूद हैं. आइए, उन्हें स्टाइल करके सीन पर ओवरले करते हैं.

इन बटन पर स्टाइल लागू करने के लिए, हम static styles प्रॉपर्टी पर वापस जाते हैं. इन स्टाइल के दायरे में आते हैं. इसका मतलब है कि ये सिर्फ़ इस वेब कॉम्पोनेंट में मौजूद एलिमेंट पर लागू होंगे. यह वेब कॉम्पोनेंट को लिखने का एक बेहतरीन अनुभव है: सिलेक्टर को इस्तेमाल करना आसान हो सकता है. इसके अलावा, सीएसएस को पढ़ना और लिखना ज़्यादा आसान हो जाएगा. अलविदा, BEM!

स्टाइल अपडेट करें, ताकि वे इस तरह दिखें:

export class BrickViewer extends LitElement {
  static styles = css`
    :host {
      display: block;
      position: relative;
    }
    #controls {
      position: absolute;
      bottom: 0;
      width: 100%;
      display: flex;
    }
  `;
}

रीस्टार्ट, पीछे जाएं, और आगे बढ़ें बटन वाला ब्रिक-व्यूअर एलिमेंट.

कैमरा रीसेट करने का बटन

हमारे <brick-viewer> के असली उपयोगकर्ता, माउस कंट्रोल का इस्तेमाल करके सीन को घुमा सकते हैं. बटन जोड़ते समय, कैमरे को उसकी डिफ़ॉल्ट पोज़िशन पर रीसेट करने के लिए एक बटन जोड़ें. क्लिक इवेंट बाइंडिंग वाला कोई दूसरा <mwc-icon-button> काम करेगा.

export class BrickViewer extends LitElement {
  private _resetCamera() {
    this._controls.reset();
  }

  render() {
    return html`
      <div id="controls">
        <!-- ... -->
        <!-- Add this button: -->
        <mwc-icon-button @click=${this._resetCamera} icon="center_focus_strong"></mwc-icon-button>
      </div>
    `;
  }
}

ज़्यादा तेज़ नेविगेशन

कुछ ब्रिक सेट में बहुत सारे चरण होते हैं. ऐसा हो सकता है कि कोई उपयोगकर्ता किसी खास चरण को स्किप करना चाहे. चरण संख्याओं के साथ स्लाइडर जोड़ने से, तेज़ी से नेविगेट करने में मदद मिल सकती है. इसके लिए, हम <mwc-slider> एलिमेंट का इस्तेमाल करेंगे.

एमडब्ल्यूसी-स्लाइडर

स्लाइडर एलिमेंट को ज़रूरी डेटा के कुछ हिस्सों की ज़रूरत होती है. जैसे, स्लाइडर की कम से कम और ज़्यादा से ज़्यादा वैल्यू. स्लाइडर की कम से कम वैल्यू हमेशा "1" हो सकती है. अगर मॉडल लोड हो गया है, तो स्लाइडर की ज़्यादा से ज़्यादा वैल्यू this._numConstructionSteps होनी चाहिए. हम <mwc-slider> को उसके एट्रिब्यूट की मदद से ये वैल्यू बता सकते हैं. अगर _numConstructionSteps प्रॉपर्टी के बारे में नहीं बताया गया है, तो हम max एट्रिब्यूट को सेट करने से बचने के लिए, ifDefined lit-html directive का इस्तेमाल भी कर सकते हैं.

"वापस जाएं" और "आगे बढ़ें" बटन के बीच <mwc-slider> जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      <div id="controls">
        <!-- ... backwards button -->
        <!-- Add this slider: -->
        <mwc-slider
            step="1"
            pin
            markers
            min="1"
            max=${ifDefined(this._numConstructionSteps)}
        ></mwc-slider>
        <!-- ... forwards button -->
      </div>
    `;
  }
}

डेटा "ऊपर"

जब कोई उपयोगकर्ता स्लाइडर को आगे-पीछे करता है, तो मॉडल बनाने का मौजूदा चरण बदल जाना चाहिए. साथ ही, मॉडल की विज़िबिलिटी को उसी हिसाब से अपडेट किया जाना चाहिए. जब भी स्लाइडर को खींचा जाएगा, तब स्लाइडर एलिमेंट एक इनपुट इवेंट उत्सर्जित करेगा. इस इवेंट को कैप्चर करने और कॉन्स्ट्रक्शन का चरण बदलने के लिए, स्लाइडर पर इवेंट बाइंडिंग जोड़ें.

इवेंट बाइंडिंग जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      <div id="controls">
        <!-- ...  -->
        <!-- Add the @input event binding: -->
        <mwc-slider
            ...
            @input=${(e: CustomEvent) => this.step = e.detail.value}
        ></mwc-slider>
        <!-- ... -->
      </div>
    `;
  }
}

वाह! स्लाइडर का इस्तेमाल करके, हम यह तय कर सकते हैं कि कौनसा चरण दिखाया जाए.

डेटा "कम"

एक और चीज़ है. चरण बदलने के लिए "वापस जाएं" और "आगे बढ़ें" बटन का इस्तेमाल करने पर, स्लाइडर हैंडल को अपडेट करना होगा. <mwc-slider> की वैल्यू एट्रिब्यूट को this.step से बाइंड करें.

value बाइंडिंग जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      <div id="controls">
        <!-- ...  -->
        <!-- Add the value property binding: -->
        <mwc-slider
            ...
            value=${ifDefined(this.step)}
        ></mwc-slider>
        <!-- ... -->
      </div>
    `;
  }
}

स्लाइडर का काम करीब-करीब पूरा हो गया है. इसे अन्य कंट्रोल के साथ अच्छे से चलाने के लिए कोई फ़्लेक्सिबल स्टाइल जोड़ें:

export class BrickViewer extends LitElement {
  static styles = css`
    /* ... */
    mwc-slider {
      flex-grow: 1;
    }
  `;
}

साथ ही, हमें स्लाइडर एलिमेंट पर ही layout को कॉल करना होगा. हम firstUpdated लाइफ़साइकल के तरीके में ऐसा करेंगे. इसे पहली बार डीओएम लेआउट होने के बाद कॉल किया जाता है. query डेकोरेटर से, हमें टेंप्लेट में स्लाइडर एलिमेंट का रेफ़रंस पाने में मदद मिल सकती है.

export class BrickViewer extends LitElement {
  @query('mwc-slider')
  slider!: Slider|null;

  async firstUpdated() {
    if (this.slider) {
      await this.slider.updateComplete
      this.slider.layout();
    }
  }
}

यहां स्लाइडर में जोड़ी जाने वाली सभी चीज़ों की जानकारी दी गई है (स्लाइडर पर अतिरिक्त pin और markers एट्रिब्यूट जोड़कर इसे बढ़िया तरीके से दिखाया गया है):

export class BrickViewer extends LitElement {
 @query('mwc-slider')
 slider!: Slider|null;

 static styles = css`
   /* ... */
   mwc-slider {
     flex-grow: 1;
   }
 `;

 async firstUpdated() {
   if (this.slider) {
     await this.slider.updateComplete
     this.slider.layout();
   }
 }

 render() {
   return html`
     ${this._renderer.domElement}
     <div id="controls">
       <mwc-icon-button @click=${this._restart} icon="replay"></mwc-icon-button>
       <mwc-icon-button @click=${this._stepBack} icon="navigate_before"></mwc-icon-button>
       <mwc-slider
         step="1"
         pin
         markers
         min="1"
         max=${ifDefined(this._numConstructionSteps)}
         ?disabled=${this._numConstructionSteps === undefined}
         value=${ifDefined(this.step)}
         @input=${(e: CustomEvent) => this.constructionStep = e.detail.value}
       ></mwc-slider>
       <mwc-icon-button @click=${this._stepForward} icon="navigate_next"></mwc-icon-button>
       <mwc-icon-button @click=${this._resetCamera} icon="center_focus_strong"></mwc-icon-button>
     </div>
   `;
 }
}

यह रहा फ़ाइनल प्रॉडक्ट!

ब्रिक-व्यूअर एलिमेंट की मदद से, कार के ब्रिक मॉडल पर नेविगेट करना

7. नतीजा

हमने अपना एचटीएमएल एलिमेंट बनाने के लिए, lit-element का इस्तेमाल करने के बारे में काफ़ी कुछ सीखा. हमने ये काम करने का तरीका जाना:

  • कस्टम एलिमेंट तय करना
  • एट्रिब्यूट एपीआई का एलान करना
  • कस्टम एलिमेंट के लिए व्यू रेंडर करना
  • स्टाइल को एनकैप्सुलेट करना
  • डेटा भेजने के लिए इवेंट और प्रॉपर्टी का इस्तेमाल करना

अगर आपको lit-element के बारे में ज़्यादा जानना है, तो इसकी आधिकारिक साइट पर जाएं.

stackblitz.com/edit/brick-viewer-complete पर जाकर, पूरा किया गया ब्रिक-व्यूअर एलिमेंट देखा जा सकता है.

brick-viewer को NPM पर भी उपलब्ध कराया गया है. इसका सोर्स यहां देखा जा सकता है: GitHub repo.