إضافة علامات وصور متحركة إلى خريطة ثلاثية الأبعاد تبدو كصورة فوتوغرافية

1. قبل البدء

يتناول هذا البرنامج التعليمي كيفية إضافة العلامات الثلاثية الأبعاد وتنسيقها في تطبيقك. ستتعرّف أيضًا على كيفية إضافة مؤثرات متحركة إلى تطبيقك من خلال التنقّل إلى مواقع جغرافية معيّنة والتجوّل فيها.

يستند هذا الدليل التعليمي إلى المفاهيم التي تم تناولها في codelab الأول. يُرجى إكمال هذا الدليل التعليمي للحصول على المعرفة الأساسية اللازمة لاستخدام هذا التطبيق، إذا لم يسبق لك ذلك.

المهام التي ستنفّذها

"الخريطة الكاملة مع العلامات

يوفّر هذا التطبيق نظرة عامة على مكاتب Google الرئيسية في أوروبا. يمكن للمستخدمين اختيار مكتب والتحليق حوله لاستكشافه، ثم التصغير للعودة إلى العرض العام. وتوفّر هذه الميزات، التي تتوفر عادةً في تطبيقات السفر والاستكشاف، تجربة أكثر تفاعلية للمستخدمين.

في هذا الدليل التعليمي حول الرموز البرمجية، ستنشئ تطبيق ويب ثلاثي الأبعاد يؤدي ما يلي:

  • يتم تحميل واجهة برمجة التطبيقات Maps JavaScript API ديناميكيًا.
  • تُضيف علامات ثلاثية الأبعاد إلى الخريطة.
  • تنسيق العلامات باستخدام ملفات SVG
  • تضيف هذه الميزة إمكانية الطيران إلى العلامات وحولها.
  • تُلخِّص المواقع الجغرافية من الرمز إلى صفيف.

المُعطيات

  • آلية عمل العلامات
  • كيفية وضع تنسيق على العلامات
  • آلية عمل الصور المتحركة مع الوظائف المضمّنة
  • عرض مواضع الكاميرات مقابل مواضع النقاط لتحسين وضع الإطار
  • نصائح مفيدة لضبط مَعلمات الكاميرا لتصوير العناصر بشكل أفضل

المتطلبات الأساسية

عليك الاطّلاع على العناصر الواردة هنا لإكمال هذا الدليل التعليمي. إذا كنت على دراية بالعمل مع Google Maps Platform، يمكنك الانتقال إلى Codelab.

منتجات "منصة خرائط Google" المطلوبة

في هذا الدليل التعليمي حول رموز البرامج، ستستخدم منتجات "منصّة خرائط Google" التالية:

  • Maps JavaScript API

متطلبات أخرى لهذا الدرس التطبيقي حول الترميز

لإكمال هذا الدليل التعليمي حول الرموز البرمجية، ستحتاج إلى الحسابات والخدمات والأدوات التالية:

  • حساب Google Cloud تم تفعيل الفوترة فيه
  • مفتاح واجهة برمجة تطبيقات Google Maps Platform مع تفعيل واجهة برمجة تطبيقات JavaScript لخرائط Google
  • معرفة أساسية بلغات JavaScript وHTML وCSS
  • محرِّر نصوص أو بيئة تطوير متكاملة من اختيارك لحفظ ملف وتعديله وعرضه
  • متصفح ويب لعرض الملف أثناء العمل عليه

2. الإعداد

إعداد "منصة خرائط Google"

إذا لم يكن لديك حساب على Google Cloud Platform ومشروع تم تفعيل ميزة الفوترة فيه، يُرجى الاطّلاع على دليل البدء في استخدام Google Maps Platform لإنشاء حساب فوترة ومشروع.

  1. في Cloud Console، انقر على القائمة المنسدلة للمشروع واختَر المشروع الذي تريد استخدامه في هذا الدليل التعليمي.

  1. فعِّل واجهات برمجة تطبيقات Google Maps Platform وحِزم SDK المطلوبة لهذا الدليل التعليمي في Google Cloud Marketplace. لإجراء ذلك، اتّبِع الخطوات الواردة في هذا الفيديو أو هذه المستندات.
  2. أنشئ مفتاح واجهة برمجة التطبيقات في صفحة بيانات الاعتماد في Cloud Console. يمكنك اتّباع الخطوات الواردة في هذا الفيديو أو هذه المستندات. تتطلّب جميع الطلبات المرسَلة إلى "منصّة خرائط Google" مفتاح واجهة برمجة التطبيقات.

3- كرة أرضية بسيطة

لبدء إنشاء التطبيق، من الضروري إجراء الإعداد الأساسي. سيؤدي ذلك إلى عرض صورة "كالكرة الزرقاء" للأرض بصورتها الأساسية، كما هو موضّح في الصورة:

"صورة تعرض الكرة الأرضية أثناء عملية الإعداد الأولي

إضافة رمز الصفحة التمهيدية

لإضافة الكرة الأرضية إلى الموقع الإلكتروني، عليك إضافة الرمز التالي إلى صفحتك. سيؤدي ذلك إلى إضافة قسم لتحميل Maps Javascript API ووظيفة init التي تنشئ عنصر الخريطة الثلاثية الأبعاد داخل الصفحة التي ستضيف إليها رمز العلامات.

احرص على إضافة مفتاحك الخاص (الذي تم إنشاؤه في قسم الإعداد) إلى الصفحة، وإلا لن تتمكّن من بدء تشغيل العنصر الثلاثي الأبعاد.

<!DOCTYPE html>
<html>
   <head>
       <title>Step 1 - Simple Globe</title>
       <style>
           body {
               height: 100vh;
               margin: 0;
           }
       </style>
   </head>

   <body>
       <script>
           (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
               key: "<INSERT API KEY>",
               v: "alpha",
               // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
               // Add other bootstrap parameters as needed, using camel case.
           });
       </script>
       <script>
           let map3D = null;

           async function init() {
               const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");

               map3D = new Map3DElement({
                   mode: MapMode.HYBRID,
               });

               document.body.append(map3D);
           }
           init();
       </script>
   </body>
</html>

بعد الانتهاء من ذلك، تكون مستعدًا لبدء وضع حدود للموقع الجغرافي المعنيّ، ويمكنك إجراء ذلك في الخطوة التالية.

4. عرض الإطار الأول

بعد أن أنشأت خريطة بعرض الكرة الأرضية، تكون خطوة التنفيذ التالية هي وضع إطار للموقع الجغرافي الصحيح لنقطة البداية. يتيح ذلك للمستخدم الحصول على نظرة عامة فورية على مكان عمله.

على الرغم من أنّ هذا المثال يركّز على مكاتب Google في أوروبا، يمكنك تطبيق هذا النهج على أي موقع جغرافي في جميع أنحاء العالم، بدءًا من بلد بأكمله وانتهاءً بمجموعة من المباني في مدينة واحدة. تتيح لك سرعة المنتج ومرونته توسيع نطاق تطبيقك من مستوى عالمي إلى مستوى محلي مع إجراء الحد الأدنى من التغييرات على الرموز البرمجية.

ستبدأ بوضع الإطار الأوّلي لجعل الخريطة الثلاثية الأبعاد تبدو على النحو التالي:

&quot;كرة أرضية تركّز على أوروبا

توجيه الكاميرا نحو أوروبا

للحصول على العرض كما هو موضّح، عليك وضع الشاشة بشكل صحيح كما لو كنت بصدد وضع كاميرا في الفضاء تطلّ على الموقع الجغرافي.

ولإجراء ذلك، يمكن استخدام عدد من المَعلمات في عنصر التحكّم في الخريطة لضبط تفاصيل الكاميرا. يمكنك الاطّلاع على كيفية تفاعل المَعلمات في الرسم البياني "الحيّ". على وجه التحديد، هناك نقطة المركز التي تنظر إليها الكاميرا والمسافة التي تبعدها عن المكان الذي تنظر إليه (النطاق). عليك أيضًا ضبط إمالة منظور الكاميرا (وإلا ستنظر مباشرةً إلى الأرض).

&quot;صورة تعرض مَعلمات الكاميرا

الإعداد النهائي، وهو الاتجاه، يحدِّد اتجاه الكاميرا. ويتم قياسه على أنّه الانحراف عن الشمال. يتم تطبيق هذه القيم على عنصر "الخريطة الثلاثية الأبعاد" ككائن لإعداد العرض الأولي. يمكنك الاطّلاع على ذلك في الرمز باستخدام أداة إنشاء العناصر الثلاثية الأبعاد المعدَّلة.

map3D = new Map3DElement({
    center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
    range: 5814650,
    tilt: 33,
    heading: 4.36,
    mode: MapMode.HYBRID
});

مَعلمات الكاميرا لالتقاط الصور

يتطلّب وضع إطار لعرض في خريطة ثلاثية الأبعاد وضع الكاميرا بدقة، ما قد يكون من الصعب تحقيقه من خلال الرمز البرمجي وحده. لتبسيط هذه العملية، يمكنك استخدام هذه الحيلة المفيدة: أضِف دالة إلى صفحتك تلتقط مَعلمات الكاميرا عند النقر على العرض المطلوب. سيتم عرض المَعلمات في وحدة التحكّم، وستكون جاهزة للنسخ إلى إعدادات كاميرا الجسم.

يمكنك العثور على الرمز الذي قد تريد استخدامه لاحقًا، ويتمّ إضافته إلى عيّنة هذه الصفحة المعروضة، على الرغم من أنّه لن يظهر في عيّنة الصفحات اللاحقة لأنّه غير مطلوب في ورشة رموز البرامج، ولكن عليك تذكُّره إذا كنت تريد إنشاء عروض توضيحية أكثر تشويقًا من خلال وضع أفضل للكاميرا.

map3D.addEventListener('gmp-click', (event) => {
   console.log("camera: { center: { lat: " + map3D.center.lat + ", lng : " + map3D.center.lng + ", altitude: " + map3D.center.altitude + " }, range: " + map3D.range + ", tilt: " + map3D.tilt + " ,heading: " + map3D.heading + ", }");
   console.log("{ lat: " + event.position.lat + ", lng : " + event.position.lng + ", altitude: " + event.position.altitude + " }");
   // Stop the camera animation when the map is clicked.
   map3D.stopCameraAnimation();
});

يُرجى ملاحظة استخدام الدالة stopCameraAnimation. إذا كانت الصفحة تكبِّر أو تصغِّر، من المفيد أن تتمكّن من إيقاف الصورة المتحركة لتتمكّن من التقاط الموقع الجغرافي في العرض في تلك اللحظة. تتيح لك هذه القطعة من الرمز البرمجي إجراء ذلك. يمكنك الاطّلاع على مزيد من التفاصيل في مستندات stopCameraAnimation.

مثال على الناتج من النقرة، كما هو موضّح في وحدة التحكّم

camera: { center: { lat: 51.39870122020001, lng : -0.08573187165829443, altitude: 51.66845062662254 }, range: 716.4743880553578, tilt: 50.5766672986501 ,heading: -1.048260134782318, }
step2.html:40 { lat: 51.398158351120536, lng : -0.08561139388593597, altitude: 51.860469133677626 }

يمكن استخدام نص الكاميرا كمدخل json في مجموعة متنوعة من العناصر في الخرائط الثلاثية الأبعاد، والإخراج الثاني هو الموقع الجغرافي الفعلي للنقطة التي حدثت فيها النقرة، وهو مفيد أيضًا لإنشاء نقاط أو أي شيء لتحديد موضع العلامات.

بعد وضع إطار للصفحة بشكل صحيح، يمكنك الآن إضافة علامات. انتقِل إلى الخطوة التالية لمعرفة كيفية إجراء ذلك.

حلّ القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

<!DOCTYPE html>
<html>

<head>
   <title>Step 2 - Europe View</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
<script>
       let map3D = null;

       async function init() {
           const { Map3DElement, MapMode } = await google.maps.importLibrary("maps3d");

           map3D = new Map3DElement({
                center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
                range: 5814650,
                tilt: 33,
                heading: 4.36,
                mode: MapMode.HYBRID,
            });

           map3D.addEventListener('gmp-click', (event) => {
               console.log("camera: { center: { lat: " + map3D.center.lat + ", lng : " + map3D.center.lng + ", altitude: " + map3D.center.altitude + " }, range: " + map3D.range + ", tilt: " + map3D.tilt + " ,heading: " + map3D.heading + ", }");
               console.log("{ lat: " + event.position.lat + ", lng : " + event.position.lng + ", altitude: " + event.position.altitude + " }");

               map3D.stopCameraAnimation();
           });

           document.body.append(map3D);
       }
       init();
   </script>

</body>

</html>

5- علامة بسيطة

في هذا القسم، ستتعرّف على كيفية إضافة العلامة الأولى. أولاً، ستتعرّف على تفاصيل عامة عن العلامات.

تتيح الخرائط الثلاثية الأبعاد إنشاء فئتين مختلفتين من العلامات، وهما فئة Marker3DElement وفئة Marker3DInteractiveElement، ويتم تحديد اختيارهما حسب ما إذا كنت تريد تفعيل النقرات على العلامات أم لا. بخلاف ذلك، فإنّهما متطابقان بشكل أساسي، لذا عليك أولاً إنشاء عنصر Marker3DElement ثم "ترقيته" إلى Marker3DInteractiveElement في الخطوات المستقبلية.

يمكنك الاطّلاع على الحلّ الكامل لهذه الخطوة هنا:

&quot;كرة أرضية بها علامة تشير إلى الخطوة المكتملة

إضافة بعض الارتفاع إلى العلامات

أول ما يجب معرفته هو أنّ العلامات ثلاثية الأبعاد مثل كل العناصر الأخرى في الخريطة الثلاثية الأبعاد. وهذا يعني أنّ الموقع الجغرافي يمكن أن يكون له ارتفاع (إرتفاع) ويمكن أن يمثّل هذا الارتفاع موضعًا بالنسبة إلى مستوى سطح البحر أو الأرض أو الشبكة أو يمكن ضبطه لتثبيته على الأرض وتجاهل الموقع الجغرافي للارتفاع. يمكنك الاطّلاع على مزيد من التفاصيل في قسم "ثوابت الارتفاع" في مستندات AltitudeMode.

يمكنك أيضًا ضبط ما إذا كان سيتمّ تمديد العلامة أم لا باستخدام القيمة extruded. سيحدِّد هذا الخيار ما إذا كان سيتم رسم خط صغير للعلامة يمتد إلى الأرض لمساعدتها في عرض الموضع الفعلي بالنسبة إلى الارتفاع، وهو أمر مفيد لاختيار نقاط على الأرض. يمكنك الاطّلاع على مثال على ذلك في موقع Google في المملكة المتحدة. تمّت توسيع كلاهما وتم ضبط موضعهما على ارتفاع مطلق. الأول على بُعد 75 مترًا والثاني على بُعد 125 مترًا.

علامة على ارتفاع 75 مترًا

علامة على بُعد 125 مترًا

الارتفاع 75 مترًا.

الارتفاع 125 مترًا.

إخفاء العلامات أو إظهارها عند حدوث حجب أو تصادم

قد لا يكون ذلك مهمًا في العرض التوضيحي، لأنّ مواضع العلامات بعيدة جدًا عن بعضها، ولكن بالنسبة إلى العلامات التي قد تتداخل مع بعضها أو قد تقع خلف المباني، يمكنك التحكّم في ما يحدث لها باستخدام قيم collisionBehavior أو drawsWhenOccluded.

بالنسبة إلى سلوك التصادم، تتوفّر لك الخيارات التالية:

  • REQUIRED: (الإعداد التلقائي) عرض العلامة دائمًا بغض النظر عن حدوث تصادم
  • OPTIONAL_AND_HIDES_LOWER_PRIORITY لا تعرض العلامة إلا إذا لم تكن تتداخل مع علامات أخرى. إذا كان هناك علامتان من هذا النوع تتداخلان، يتم عرض العلامة التي تحقّق قيمة أعلى من zIndex. إذا كانت السمة zIndex متطابقة، يتم عرض العنصر الذي يظهر في موضع أسفل الشاشة.
  • REQUIRED_AND_HIDES_OPTIONAL عرض العلامة دائمًا بغض النظر عن حدوث تداخل، وإخفاء أي علامات أو تصنيفات OPTIONAL_AND_HIDES_LOWER_PRIORITY قد تتداخل مع العلامة

تظهر في الصور الاختلافات في كيفية عرض العلامات استنادًا إلى سلوك التصادم المحدّد. يتم عرض جميع العلامات عند ضبط REQUIRED، ولكن إذا استخدمت REQUIRED_AND_HIDES_OPTIONAL، سيتم في هذه الحالة عرض العلامات في أسفل الشاشة (يمكنك استخدام zIndex لعرض علامات أخرى في أعلى الشاشة إذا أردت).

يتم عرض جميع العلامات على النحو المطلوب

علامات تحجب علامات أخرى

مطلوبة

REQUIRED_AND_HIDES_OPTIONAL

بالنسبة إلى حجب الرؤية، يمكنك اختيار رسم العلامات خلف المباني أو عدم رسمها. يظهر ذلك في الصورة التالية. عند ضبط drawsWhenOccluded على true، يتم عرض العلامات بشكل خافت قليلاً عند رسمها خلف المباني، وعند ضبطها على false، يتم إخفاء العلامات عندما تكون خلف مبنى. يمكنك الاطّلاع على مزيد من التفاصيل في الجدول التالي:

صورة تعرض خريطة تحجب العلامات المُحجوبة

صورة تعرض خريطة تعرض علامات محجوبة

drawsWhenOccluded : false

drawsWhenOccluded : true

كما ذكرنا، سيتم عرض العلامات المخفية بسبب التصادم بشكل خافت إذا كان رسم العلامات المُحجوبة مسموحًا به. في الصورة، يمكنك رؤية بعض العلامات التي تحجبها المباني وبعضها الآخر الذي تحجبه علامات أخرى.

&quot;صورة تعرض عددًا من العلامات وتأثير حجب الرؤية

يُرجى الرجوع إلى مثال سلوك التصادم في خريطة ثنائية الأبعاد للحصول على مزيد من التفاصيل.

محو لوحة الرسم

حان الآن وقت إنشاء العلامة الأولى. لضمان تركيز المستخدِم على العلامات، يمكنك إيقاف التصنيفات التلقائية في الخريطة الثلاثية الأبعاد.

اضبط قيمة mode لعنصر الخريطة الثلاثية الأبعاد على SATELLITE.

لمزيد من المعلومات، يُرجى الاطّلاع على mode.

map3D = new Map3DElement({
    center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
    range: 5814650,
    tilt: 33,
    heading: 4.36,
    mode: MapMode.SATELLITE
});

ينتج عن ذلك الخريطة الثلاثية الأبعاد التالية:

‎“Image of Europe without borders and text.

إضافة العلامة الأولى

بعد تنظيف اللوحة، يمكنك الآن إضافة العلامة الأولى. تشمل المَعلمات الرئيسية موضع العنصر وتصنيفه.

لإضافة علامة، اضبط موضع العلامة. يمكنك أيضًا تضمين تصنيف يظهر فوق العلامة وعناصر أخرى كما هو موضّح في مستندات Marker3DElement.

لإضافة العلامة، عليك إضافة الرمز البرمجي التالي بعد السطر الذي يخفي التصنيفات التلقائية كما هو موضّح:

const marker = new Marker3DElement({
   position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
   label: 'Google UK',
   altitudeMode: 'ABSOLUTE',
   extruded: true,
});

map3D.append(marker);

بعد إنشاء العلامة، أضِفها إلى الخريطة الثلاثية الأبعاد باستخدام طريقة الإضافة. تذكَّر أنّه يتم تخزين العلامات كصفيف من العناصر الفرعية داخل الخريطة الثلاثية الأبعاد. لتعديل علامة، عليك الوصول إليها من خلال هذه الصفيف.

تأكَّد من تحميل Marker3DElement من واجهة برمجة التطبيقات Maps JavaScript API من خلال إضافتها إلى قائمة المكتبات عند تحميل واجهة برمجة التطبيقات.

const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");

عند تحميل الصفحة الآن، ستظهر أوروبا بأكملها مع علامة فوق المكتب في لندن. كما هو موضّح في الصورة المتحركة، يمكنك تكبير الشاشة يدويًا لرؤية العلامة فوق الموقع الجغرافي الذي تم إنشاؤه.

&quot;صورة متحركة تعرض تكبيرًا يدويًا لموقع Google UK الإلكتروني.

بعد تحميل العلامة الأولى، تكون الخطوة التالية هي تحسين مظهرها.

حلّ المشكلة في القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

<!DOCTYPE html>
<html>

<head>
   <title>Step 3 - Simple Marker</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       async function init() {
            const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");

            map3D = new Map3DElement({
                center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
                range: 5814650,
                tilt: 33,
                heading: 4.36,
                mode: MapMode.SATELLITE,
            });

           const marker = new Marker3DElement({
               position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
               label: 'Google UK',
               altitudeMode: 'ABSOLUTE',
               extruded: true,
           });
           map3D.append(marker);

           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

6. علامة SVG

في هذه الخطوة، ستجعل العلامة تبدو أجمل من خلال تغيير العلامة لإضافة علم إلى العلامة لتمثيل البلد الذي تقع فيه. لنطّلِع على كيفية إجراء ذلك، وعليك التعرّف على PinElement.

في النهاية، ستحصل على مظهر جديد كما هو موضّح:

&quot;صورة تتضمّن علامة عليها علم المملكة المتحدة&quot;

تخصيص أساسي باستخدام PinElement

إنّ PinElement هو أحد العناصر المشتركة بين العلامات في واجهة برمجة التطبيقات JavaScript، سواء كانت هذه الخرائط ثنائية أو ثلاثية الأبعاد. أثناء إضافة Marker3DElement إلى Map3DElement، تضيف PinElement إلى Marker3DElement كعنصر فرعي لهذا العنصر.

يحتوي PinElement على إمكانية تغيير العلامة العادية على مستوى أساسي لضبط لون الحدود والنقطة الداخلية (أو الرمز) ولون الخلفية. يمكنك الاطّلاع على هذه القيم في الصورة التي تعرض علامة ثنائية الأبعاد.

‎“Image with options for marker pin customisation”‎

يمكنك أيضًا ضبط حجم العلامة من خلال العنصر عن طريق ضبط قيمة المقياس (>1 أكبر من المعتاد و <1 أصغر كنسبة مئوية).

يمكنك أيضًا استبدال الرمز بملف صورة أو svg إذا كنت تريد إضفاء مظهر مخصّص أكثر مع الحفاظ على مظهر دبوس الخريطة العادي في PinElement.

استخدامات أخرى لواجهة برمجة التطبيقات PinElements

في هذه الخطوة، ستُعدّل الرمز العادي PinElement باستخدام علامة svg وألوان مختلفة، ولكن من المهم أيضًا معرفة أنّه يمكنك تغيير مظهر العلامة تمامًا حتى لا تبدو مثل دبوس الخريطة. ضمن العلامة، يمكنك أيضًا إدراج رسومات جديدة باستخدام النماذج، مثل HTMLImageElement وSVGElement. يمكنك الاطّلاع على مزيد من التفاصيل حول كيفية إجراء ذلك في المستند Marker3DElement-Slots.

لمعرفة ما هو ممكن بالكامل، اطّلِع على العيّنات التالية التي تعرض أمثلة على تنسيق العلامات باستخدام عدد من الأساليب المختلفة.

صورة تعرض تخصيص العلامة الأساسية

صورة تعرض تخصيص علامة معقدة

العلامات التي تتضمّن تخصيصًا أساسيًا من خلال PinElement، اطّلِع على عيّنات.

العلامات التي تتضمّن تخصيصًا معقّدًا من خلال النموذج من خلال SVG والصور، اطّلِع على عيّنات.

إضافة PinElement

لتغيير مظهر العلامة، يجب أولاً التأكّد من إضافة مكتبة PinElement إلى الصفحة. ويتم ذلك من خلال إضافة السطر التالي من التعليمات البرمجية بعد استيراد مكتبة maps3d:

const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');

بعد تحميل العنصر، يمكن الإشارة إلى PinElement وإنشاؤه. اطّلِع على الرمز البرمجي وأضِفه بين المكان الذي يتم فيه إنشاء العلامة وإلحاق العلامة بالخريطة الثلاثية الأبعاد.

const marker = new Marker3DElement({
   position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
   label: 'Google UK',
   altitudeMode: 'ABSOLUTE',
   extruded: true,
});

const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

const markerPin = new PinElement({
   "background": 'white',
   "glyph": new URL(base + '/images/gb.svg'),
   "scale": 1.0,
});
marker.append(markerPin);

map3D.append(marker);

بما أنّك لا تحمّل مجرد دبوس أساسي، هناك عدد من الإجراءات التي يجب تنفيذها إلى جانب إعداد PinElement مع لون الخلفية وحجمها المرتبطَين به.

أولاً، يجب إنشاء إشارة إلى صورة svg لرمز العلم، وهو علم الاتحاد في هذه الحالة. يمكنك الحصول عليها من مجموعة مثل هذه المجموعة على الرابط https://flagicons.lipis.dev/.

بعد الحصول على الرمز، يمكنك وضعه في مكان يمكن للموقع الإلكتروني تحديد موقعه الجغرافي، وفي هذه الحالة يمكنك إما ترميز الموقع الجغرافي للصورة بشكل ثابت أو استخدام الموقع الجغرافي الحالي للموقع الإلكتروني كجزء من الدليل، كما هو موضّح هنا باستخدام المتغيّر الأساسي. يمكنك بعد ذلك ربط هذا الرمز بالمكان على الخادم بالرمز الصحيح، والذي يقع هنا ضمن ‎'/images/gb.svg'.

يؤدي ذلك إلى إنشاء عنصر PinElement يشبه العنصر المعروض:

&quot;علامة تحدِّد رمز علم الاتحاد Jack

بعد وضع العلامة في المكان الصحيح ووضع الرمز في المكان الصحيح، من المفترض أن تظهر لك خريطة ثلاثية الأبعاد بالشكل التالي:

&quot;تكبير العلامة الجديدة.

بعد أن تم تحسين العلامة، يمكن أيضًا تغييرها لجعلها قابلة للنقر للسماح بإضافة تفاعل. سيتم إجراء ذلك في الخطوة التالية.

حلّ القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

لا تنسَ أيضًا أنّك ستحتاج إلى الحصول على ملف svg للعلم (أو ملف png من اختيارك) وتخزينه في دليل يمكن العثور عليه من خلال صفحتك (هنا يتم تخزينه في مجلد "الصور").

<!DOCTYPE html>
<html>

<head>
   <title>Step 4 - SVG Marker</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       async function init() {
           const { Map3DElement, MapMode, Marker3DElement } = await google.maps.importLibrary("maps3d");
           const { PinElement } = await google.maps.importLibrary('marker');

           map3D = new Map3DElement({
                center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
                range: 5814650,
                tilt: 33,
                heading: 4.36,
                mode: MapMode.SATELLITE,
           });

           const marker = new Marker3DElement({
               position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
               label: 'Google UK',
               altitudeMode: 'ABSOLUTE',
               extruded: true,
           });

           const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

           const markerPin = new PinElement({
               "background": 'white',
               "glyph": new URL(base + '/images/gb.svg'),
               "scale": 1.0,
           });
           marker.append(markerPin);

           map3D.append(marker);

           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

7- علامة تفاعلية

في الخطوة الأخيرة، تمت إضافة علامة إلى الصفحة، ولكن بخلاف المظهر الجميل، لا تؤدي هذه العلامة إلى الكثير من الإجراءات، وسيظل عليك التفاعل مع الخريطة الثلاثية الأبعاد بالطريقة نفسها. الخطوة التالية هي إضافة إمكانية تنفيذ إجراء ما باستخدام العلامة عند النقر عليها، ما يسمح للعلامة بالتفاعل مع المستخدم.

لإضافة هذه الميزة، عليك تحويل Marker3DElement إلى Marker3DInteractiveElement. وفي النهاية، ستحصل على صفحة تبدو مشابهة، ولكن عند النقر على العلامة، ستظهر الآن تنبيهات وستبدو على النحو التالي:

&quot;صورة تعرض الردّ عند النقر عليها

أولاً، عليك تغيير فئة العلامة.

لإضافة تفاعل إلى علامة، عليك التأكّد من أنّها تستخدم الفئة الصحيحة. Marker3DInteractiveElement هو العنصر المطلوب، ولكن بما أنّه إضافة إلى Marker3DElement، لا تحتاج إلى اتخاذ أي إجراء سوى تحميل الفئة الجديدة وتغيير اسم الفئة في أداة الإنشاء.

const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
const { PinElement } = await google.maps.importLibrary('marker');

map3D = new Map3DElement({
    center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
    range: 5814650,
    tilt: 33,
    heading: 4.36,
    mode: MapMode.SATELLITE,
});

const marker = new Marker3DInteractiveElement({
   position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
   label: 'Google UK',
   altitudeMode: 'ABSOLUTE',
   extruded: true,
});

ثانيًا، أضِف حدث النقر إلى العلامة.

بعد ذلك، أضِف حدث نقرة إلى العلامة لمعالجة تفاعل المستخدم والاستجابة له. في المقتطف، يمكنك الاطّلاع على إضافة حدث النقر إلى العلامة. في هذه الحالة، يتمّ تشغيل تنبيه وعرض النص الذي يعرض التصنيف من العلامة، ويتم الحصول عليه من استهداف الحدث الذي تمّ تشغيله، ما يسمح لنا بالوصول إلى سمة التصنيف. أضِف الرمز البرمجي التالي إلى تطبيقك بعد إنشاء العلامة مباشرةً.

marker.addEventListener('gmp-click', (event) => {
   alert('You clicked on : ' + event.target.label);
   event.stopPropagation();
});

يُرجى العِلم أنّه يتم استخدام حدث stopPropagation للتأكّد من بدء أي مستمعين آخرين للنقر في الحزمة على العناصر الأساسية، مثل اللوحة الرئيسية للخريطة الثلاثية الأبعاد.

عند تشغيل تطبيقك الآن، من المفترض أن تظهر لك النتيجة التالية:

&quot;صورة تعرض الردّ عند النقر عليها

مع إمكانية تنفيذ إجراء عند النقر على العلامة، أصبح من الممكن الآن إضافة بعض الصور المتحركة إلى الصفحة في الخطوة التالية.

حلّ القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

<!DOCTYPE html>
<html>

<head>
   <title>Step 5 - Interactive Marker</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       async function init() {
           const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
           const { PinElement } = await google.maps.importLibrary('marker');

           map3D = new Map3DElement({
                center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
                range: 5814650,
                tilt: 33,
                heading: 4.36,
                mode: MapMode.SATELLITE,
           });

           const marker = new Marker3DInteractiveElement({
               position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
               label: 'Google UK',
               altitudeMode: 'ABSOLUTE',
               extruded: true,
           });

           marker.addEventListener('gmp-click', (event) => {
               alert('You clicked on : ' + event.target.label);
               event.stopPropagation();
           });

           const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

           const markerPin = new PinElement({
               "background": 'white',
               "glyph": new URL(base + '/images/gb.svg'),
               "scale": 1.0,
           });
           marker.append(markerPin);

           map3D.append(marker);

           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

8. الانتقال إلى

في هذه الخطوة، ستستخدم إمكانية النقر على العلامة لإضافة صورة متحركة للانتقال إلى موقعها الجغرافي. يمكنك الاطّلاع على مثال عملي على ذلك هنا.

&quot;صورة متحركة تعرض العلامة التي تم النقر عليها والانتقال إلى الموقع الجغرافي

إضافة حركة باستخدام flyCameraTo

ولإضافة ذلك إلى الصفحة، ستستخدم الطريقة flyCameraTo في "الخرائط الثلاثية الأبعاد"، حيث تتحرّك الكاميرا بين موقع الكاميرا الذي أنت فيه وموقع الكاميرا الذي تريد عرضه، مع إجراء عمليات الاستقراء بين الموقعَين وإضافة صور متحركة للرحلة داخل "الخرائط الثلاثية الأبعاد".

عند استخدام flyCameraTo، عليك تحديد FlyToAnimationOptions التي تحتوي على سمتَين، وهما endCamera، وهو الموقع الجغرافي الذي يجب أن تشير إليه الكاميرا في نهاية التأثير المتحرك، وdurationMillis، وهي المدة التي ستستغرقها عملية النقل بالمللي ثانية.

في المثال، اضبط الكاميرا لتنظر إلى المبنى الذي يمثّل موضع العلامة، مع إمالة 65 درجة، ونطاق 500 متر، وتوجيه نحو الشمال باتجاه 0 درجة. اضبط توقيت الصورة المتحركة على 12500 ملي ثانية (12.5 ثانية).

استبدِل حدث التنبيه الحالي في الصفحة بمقتطف flyCameraTo:

marker.addEventListener('gmp-click', (event) => {
   map3D.flyCameraTo({
       endCamera: {
           center: marker.position,
           tilt: 65,
           range: 500,
           heading: 0,
       },
       durationMillis: 12500,
   });

   event.stopPropagation();
});

هذا كلّ شيء، من المفترض أن تتمكّن الآن من إعادة تحميل الصفحة والنقر على العلامة والانتقال إلى Google UK، كما هو موضّح في الصورة المتحركة:

&quot;صورة متحركة تعرض العلامة التي تم النقر عليها والانتقال إلى الموقع الجغرافي

في هذه الخطوة، أضفت علامة قابلة للنقر تنقل الكاميرا إلى موقع العلامة. في الخطوة التالية، ستضيف إمكانية تحريك الكاميرا حول النقطة لتدور حول الموقع الجغرافي.

حلّ المشكلة في القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

<!DOCTYPE html>
<html>

<head>
   <title>Step 6 - Zoom To</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       async function init() {
           const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
           const { PinElement } = await google.maps.importLibrary('marker');

           map3D = new Map3DElement({
                center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
                range: 5814650,
                tilt: 33,
                heading: 4.36,
                mode: MapMode.SATELLITE,
           });

           const marker = new Marker3DInteractiveElement({
               position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
               label: 'Google UK',
               altitudeMode: 'ABSOLUTE',
               extruded: true,
           });

           marker.addEventListener('gmp-click', (event) => {
               map3D.flyCameraTo({
                   endCamera: {
                       center: marker.position,
                       tilt: 65,
                       range: 500,
                       heading: 0,
                   },
                   durationMillis: 12500,
               });

               event.stopPropagation();
           });

           const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

           const markerPin = new PinElement({
               "background": 'white',
               "glyph": new URL(base + '/images/gb.svg'),
               "scale": 1.0,
           });
           marker.append(markerPin);

           map3D.append(marker);

           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

9- التنقّل في الأرجاء

العنصر الأخير في المؤثر المتحرك هو استخدام الطريقة flyCameraAround لإنشاء تأثير متحرك للتجوّل حول المبنى. في النهاية، ستظهر لك صورة متحركة ستطير إلى المبنى ثم تطير حوله كما هو موضّح في الصورة المتحركة. قد يكون هذا الإجراء سريعًا بعض الشيء ليكون مثالاً حقيقيًا، ولكنه مفيد لعرض آلية عمل الإجراء بدون أن يكون طويلاً جدًا. يمكنك تغيير التوقيتات إلى أن تصل إلى قيمة تناسبك.

&quot;صورة متحركة تعرض علامة يتم النقر عليها ثم التحليق إلى موقع جغرافي وحوله&quot;.

لنطّلِع على بعض الأماكن.

تشبه طريقة flyCameraAround الدالة flyCameraTo من حيث أنّها تأخذ عددًا من الخيارات كمدخل يتحكّم في الموقع الجغرافي الذي سيتم الطيران حوله، مثل مَعلمات الكاميرا والوقت المستغرَق بالملي ثانية للطيران حوله. أخيرًا، يمكنك أيضًا تحديد عدد مرات التناوب التي يمكن أن تحدث في الوقت المحدّد. يمكنك الاطّلاع على جميع الخيارات هنا في FlyAroundAnimationOptions.

لكن، انتظِر دقيقة واحدة.

في الصورة المتحركة، يمكنك رؤية الصورة المتحركة وهي تطير إلى الموقع الجغرافي ثم تطير حوله، ما يؤدي إلى ربط الصور المتحركة. ولإجراء ذلك، يمكنك استخدام حدث gmp-animationend في الخرائط الثلاثية الأبعاد للتأكّد من انتهاء الحركة الحالية قبل بدء الحركة التالية. من المفترض أن تظهر هذه الصورة المتحركة مرة واحدة فقط قبل إيقافها.

اطّلِع على الرمز وأدرِجه بعد الرمز الذي أضفته في القسم السابق.

marker.addEventListener('gmp-click', (event) => {
   map3D.flyCameraTo({
       endCamera: {
           center: marker.position,
           tilt: 65,
           range: 500,
           heading: 0,
       },
       durationMillis: 5000,
   });

   map3D.addEventListener('gmp-animationend', () => {
       map3D.flyCameraAround({
           camera: {
               center: marker.position,
               tilt: 65,
               range: 500,
               heading: 0,
           },
           durationMillis: 5000,
           rounds: 1
       });
   }, { once: true });

   event.stopPropagation();
});

من خلال إضافة إمكانية الاستماع إلى حدث gmp-animationend، يمكنه بعد ذلك استدعاء حدث flyCameraAround. يؤدي ضبط نقطة البدء على النقطة نفسها التي تم استخدامها لكاميرا نهاية أسلوب الانتقال السريع إلى انتقال سلس (لعدم التسبب في أيّ حركات مفاجئة إلى موقع جديد). مرة أخرى، يتم ضبط durationMillis للتحكّم في المدة التي يستغرقها تنفيذ الحركة. في هذه الحالة، تأخذ الطريقة أيضًا خيارًا آخر، وهو rounds، ويتم ضبطه على 1.

وهذا يعني أنّ الكاميرا ستدور حول النقطة مرة واحدة في غضون 5 ثوانٍ. يمكنك تجربة هذه القيم حسب الحاجة للعثور على القيمة التي تناسبك.

في هذه المرحلة، سينتهي التأثير المتحرك، ولكن لا تريد أن يتم تشغيل الحدث gmp-animationend مرة أخرى باستخدام هذا المقطع من الرمز البرمجي، ما سيؤدي إلى تكرار المسار بشكل لانهائي. لتجنُّب ذلك، يمكن للمستمع ضبط الإعداد once ليكون مساويًا true. وهذا يعني أنّه ستتم إزالة الحدث بعد اكتماله، ما يتجنّب حدوث حلقة لا نهائية.

بعد إضافة هذا العنصر، من المفترض أن تتمكّن من تشغيل الحلّ ورؤية الصورة المتحركة الآن وهي تطير حول العلامة في النهاية، كما هو موضّح في الصورة المتحركة:

&quot;صورة متحركة تعرِض طائرة تحلّق حول علامة.

في هذه الخطوة، أضفت علامة يمكن النقر عليها، ثم تطير الكاميرا إلى موقع العلامة وحولها. في المرحلة التالية، حان وقت البدء في إضافة المزيد من النقاط والسماح لنا بالتنقّل بينها.

حلّ المشكلة في القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

<!DOCTYPE html>
<html>

<head>
   <title>Step 7 - Zoom Around</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       const europeCamera = {
           center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
           range: 5814650,
           tilt: 33,
           heading: 4.36,
       };

       async function init() {
           const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
           const { PinElement } = await google.maps.importLibrary('marker');

           map3D = new Map3DElement({
               ...europeCamera,
               mode: MapMode.SATELLITE,
           });

           const marker = new Marker3DInteractiveElement({
               position: { lat: 51.5332, lng: -0.1260, altitude: 75 },
               label: 'Google UK',
               altitudeMode: 'ABSOLUTE',
               extruded: true,
           });

           marker.addEventListener('gmp-click', (event) => {
               map3D.flyCameraTo({
                   endCamera: {
                       center: marker.position,
                       tilt: 65,
                       range: 500,
                       heading: 0,
                   },
                   durationMillis: 5000,
               });

               map3D.addEventListener('gmp-animationend', () => {
                   map3D.flyCameraAround({
                       camera: {
                           center: marker.position,
                           tilt: 65,
                           range: 500,
                           heading: 0,
                       },
                       durationMillis: 5000,
                       rounds: 1
                   });
               }, { once: true });

               event.stopPropagation();
           });

           const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

           const markerPin = new PinElement({
               "background": 'white',
               "glyph": new URL(base + '/images/gb.svg'),
               "scale": 1.0,
           });
           marker.append(markerPin);

           map3D.append(marker);

           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

10. باريس

على الرغم من أنّ لندن مدينة رائعة، إلا أنّها تبدو وحيدة بعض الشيء على الصفحة، لذا لنبدأ بإضافة بعض المواقع الجغرافية الجديدة بدءًا من باريس. لتنفيذ ذلك، يمكن استخدام صفيف لتخزين جميع التفاصيل المتعلّقة بالموقع الجغرافي، ثم استخدامها كمدخلات للدوالّ والمتغيّرات التي تحدّد مَعلمات عرض العلامة، بالإضافة إلى الانتقال إلى مواقع الكاميرا وحولها. وقد يختلف هذا الموضع، كما ذكرنا، عن موقع نقطة العلامة لأغراض وضع إطار لالتقاط لقطة أفضل للكاميرا لمبنى مثلاً.

&quot;صورة متحركة تعرض نقرة وانتقالًا إلى Google France وما حولها

صفيف المواقع الجغرافية

لكي لا تضطر إلى ترميز جميع التفاصيل حول موقع جغرافي معيّن، مثل الكاميرا المعروضة ونقطة العلامة وخيارات العرض، يمكنك استخدام مصفوفة صغيرة من عناصر json لتخزين هذه البيانات. ويمكن تطبيق ذلك بعد إنشاء العلامات واستخدامها في التطبيق. يمكنك الاطّلاع على هذا المثال في مقتطف الرمز، حيث يتم إنشاء متغيّر باسم officeLocations لتخزين الصفيف.

أضِف الرمز التالي قبل دالة init مباشرةً. يُرجى العلم أيضًا أنّه تم نقل المتغيّر الأساسي خارج دالة init لكي يمكن تطبيقه على جميع المواقع الجغرافية للمكاتب.

const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

const europeCamera = {
   center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
   range: 5814650,
   tilt: 33,
   heading: 4.36,
};

const officeLocations = [
   {
       "name": "Google France",
       "camera": {
           "center": { lat: 48.877276, lng: 2.329978, altitude: 48 },
           "range": 178,
           "tilt": 57.48,
           "heading": -17,
       },
       "point": { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
       "pin": {
           "background": 'white',
           "glyph": new URL(base + '/images/fr.svg'),
           "scale": 1.0,
       },
   },
   {
       "name": "Google UK",
       "camera": {
           "center": { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
           "range": 500,
           "tilt": 56.21672368296945,
           "heading": -31.15763027564165,
       },
       "point": { lat: 51.5332, lng: -0.1260, altitude: 75 },
       "pin": {
           "background": 'white',
           "glyph": new URL(base + '/images/gb.svg'),
           "scale": 1.0,
       },
   }]
       const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

تتضمّن كلّ موقع جغرافي لمكتب الخصائص التالية:

  • name : اسم الموقع الجغرافي
  • camera : العرض الأوّلي للاطّلاع على الموقع الجغرافي الذي تريد الانتقال إليه والتجوّل فيه.
  • point : الموقع الجغرافي لوضع العلامة.
  • pin : تفاصيل لون علامة الدبوس وخصائص الرمز

زاوية مختلفة

قد تلاحظ هنا أنّ مركز الكاميرا ونقطة العلامة متطابقان في المملكة المتحدة (باستثناء الارتفاع)، في حين أنّ الكاميرا والنقطة مختلفان في فرنسا. يرجع ذلك إلى أنّ الموقع الجغرافي في فرنسا يجب أن يكون العلامة في موقع مختلف عن عرض الكاميرا الأولي، ما يمنح عرضًا أفضل للمبنى بأكمله عند التحليق حوله وفوقه مقارنةً بما قد يتم تقديمه في حال استخدام نقطة العلامة.

الرجوع إلى أوروبا

من وظائف زيادة عدد النقاط أنّها تفرض شرطًا للتنقّل بينها. يمكنك استخدام قائمة منسدلة للسماح بالاختيار، ولكن في هذا المثال، ستعود الكاميرا إلى العرض الأوروبي في كل مرة للسماح للمستخدم باختيار موقع آخر.

ولإجراء ذلك، يجب تخزين العرض الأولي في متغيّر يمكن استخدامه لإعادة ضبط الكاميرا على العرض الكامل لأوروبا. في هذا المثال، أضِف متغيّرًا جديدًا باسم europeCamera لتخزين هذا الإجراء لاستخدامه لاحقًا.

تعديل دالة init

أول تعديل عليك إجراؤه هو استخدام عنصر europeCamera كمدخل عند إنشاء Map3DElement.

التعديل الثاني الذي عليك إجراؤه هو لفّ قسم إنشاء العلامة في حلقة لتحديثه بالمَعلمات المخزّنة في المتغيّرات، ويمكنك الاطّلاع عليها في الرمز المعروض:

  • office.point : موقع العلامة.
  • office.name : اسم المكتب المستخدَم لتصنيف العلامة
  • office.camera : الموقع الجغرافي الأولي للكاميرا
  • office.pin : خيارات PinElement للاختلافات في العرض

لا تنسَ أيضًا الحصول على ملف svg أو صورة لعلم فرنسا.

async function init() {
   const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
   const { PinElement } = await google.maps.importLibrary('marker');

   map3D = new Map3DElement({
       ...europeCamera,
       mode: MapMode.SATELLITE,
   });

   officeLocations.forEach(office => {
       const marker = new Marker3DInteractiveElement({
           position: office.point,
           label: office.name,
           altitudeMode: 'ABSOLUTE',
           extruded: true,
       });

       marker.addEventListener('gmp-click', (event) => {
           map3D.flyCameraTo({
               endCamera: office.camera,
               durationMillis: 5000,
           });

           map3D.addEventListener('gmp-animationend', () => {
               map3D.flyCameraAround({
                   camera: office.camera,
                   durationMillis: 5000,
                   rounds: 1
               });

               map3D.addEventListener('gmp-animationend', () => {
                   map3D.flyCameraTo({
                       endCamera: europeCamera,
                       durationMillis: 5000,
                   });
               }, { once: true });

           }, { once: true });

           event.stopPropagation();
       });

       const markerPin = new PinElement(office.pin);
       marker.append(markerPin);

       map3D.append(marker);
   });
   document.body.append(map3D);
}

يُرجى العلم أنّه تمت إضافة دالة gmp-animationend ثانية بعد الصورة المتحركة flyCameraAround للتعامل مع التحليق إلى العرض الأوروبي باستخدام المتغيّر europeCamera المخزّن. كما هو موضّح في الصورة المتحركة:

&quot;صورة متحركة تحلّق بين المكاتب في فرنسا والمملكة المتحدة وحولها

في هذه المرحلة، تم توسيع نطاق التطبيق ليشمل موقعَين جغرافيَّين وإمكانية التنقّل بينهما باستخدام الصور المتحركة وصفيف المواقع الجغرافية. في المرحلة التالية، ستتم إضافة بقية مواقع المكاتب إلى الصفيف.

حلّ القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

لا تنسَ أيضًا أنّك ستحتاج إلى الحصول على ملف svg للعلم (أو ملفات png حسب اختيارك) وتخزينه في دليل يمكن أن تعثر عليه صفحتك (هنا يتم تخزينه في مجلد images).

<!DOCTYPE html>
<html>

<head>
   <title>Step 8 - Paris!</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

       const europeCamera = {
           center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
           range: 5814650,
           tilt: 33,
           heading: 4.36,
       };

       const officeLocations = [
           {
               "name": "Google France",
               "camera": {
                   "center": { lat: 48.877276, lng: 2.329978, altitude: 48 },
                   "range": 178,
                   "tilt": 57.48,
                   "heading": -17,
               },
               "point": { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
               "pin": {
                   "background": 'white',
                   "glyph": new URL(base + '/images/fr.svg'),
                   "scale": 1.0,
               },
           },
           {
               "name": "Google UK",
               "camera": {
                   "center": { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
                   "range": 500,
                   "tilt": 56.21672368296945,
                   "heading": -31.15763027564165,
               },
               "point": { lat: 51.5332, lng: -0.1260, altitude: 75 },
               "pin": {
                   "background": 'white',
                   "glyph": new URL(base + '/images/gb.svg'),
                   "scale": 1.0,
               },
           }]

       async function init() {
           const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
           const { PinElement } = await google.maps.importLibrary('marker');

           map3D = new Map3DElement({
               ...europeCamera,
               mode: MapMode.SATELLITE,
           });

           officeLocations.forEach(office => {
               const marker = new Marker3DInteractiveElement({
                   position: office.point,
                   label: office.name,
                   altitudeMode: 'ABSOLUTE',
                   extruded: true,
               });

               marker.addEventListener('gmp-click', (event) => {
                   map3D.flyCameraTo({
                       endCamera: office.camera,
                       durationMillis: 5000,
                   });

                   map3D.addEventListener('gmp-animationend', () => {
                       map3D.flyCameraAround({
                           camera: office.camera,
                           durationMillis: 5000,
                           rounds: 1
                       });

                       map3D.addEventListener('gmp-animationend', () => {
                           map3D.flyCameraTo({
                               endCamera: europeCamera,
                               durationMillis: 5000,
                           });
                       }, { once: true });

                   }, { once: true });

                   event.stopPropagation();
               });

               const markerPin = new PinElement(office.pin);
               marker.append(markerPin);

               map3D.append(marker);
           });
           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

11. المزيد من الأماكن

على الرغم من أنّ التطبيق يتضمّن الآن جميع الميزات المطلوبة، لا تزال الخريطة الثلاثية الأبعاد تبدو قليلة المحتوى، لذا عليك الآن إضافة بعض المواقع الجغرافية الأخرى لجعلها أكثر كثافة. من خلال استخدام صفيف، من السهل مواصلة تعبئة مواقع جغرافية جديدة بعلامات فريدة خاصة بها. الخطوة الأخيرة هي مواصلة إضافة العلامات إلى أن تظهر لك طريقة العرض التالية.

&quot;صورة تعرض جميع المكاتب

إضافة المزيد من العلامات

لدى Google عدد من المكاتب في العديد من البلدان في أوروبا، لذا لنضيف بعضًا منها إلى الخريطة. ما عليك سوى تعديل الصفيف. يمكن الحصول على هذه البيانات من خدمة ويب أو عرضها من ملف ثابت في مكان ما، وفي حالتنا، سيتم الاحتفاظ بها في الصفحة نفسها لأغراض التبسيط.

يمكنك إضافة عدد العلامات الذي تريده، وسيتم اختيارها من خلال الصفحة ثم إضافتها تلقائيًا إلى العرض. تذكَّر الحصول على العلامات الصحيحة وتخزينها في دليل الصور (أو أي مكان آخر مناسب).

const officeLocations = [
   {
       name: "Google France",
       camera: {
           center: { lat: 48.877276, lng: 2.329978, altitude: 48 },
           range: 178,
           tilt: 57.48,
           heading: -17,
       },
       point: { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/fr.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google UK",
       camera: {
           center: { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 51.5332, lng: -0.1260, altitude: 75 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/gb.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Belgium",
       camera: {
           center: { lat: 50.83930408436509, lng: 4.38052394507952, altitude: 64.38932203802196},
           range: 466.62899893119175,
           tilt: 43.61569474716178,
           heading: 51.805907046332074,
       },
       point: { lat: 50.8392653, lng: 4.3808751, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/be.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Czechia",
       camera: {
           center: {
               lat: 50.07004093853976,
               lng: 14.402871475443956,
               altitude: 223.39574818495532
           },
           range: 522.0365799222782,
           tilt: 62.39511972890614,
           heading: -39.150149539328304,
       },
       point: { lat: 50.0703122, lng: 14.402668199999999, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/cz.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Denmark",
       details: "2, Sankt Petri Passage 5, 1165 København",
       camera: {
           center: {
               lat: 55.680359539635866,
               lng: 12.570460204526002,
               altitude: 30.447654757346044
           },
           range: 334.8786935049066,
           tilt: 55.38819319004654,
           heading: 149.63867461295067,
       },
       point: { lat: 55.6804504, lng: 12.570279099999999, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/dk.svg'),
           scale: 1.0,
       },
   },
   ,
   {
       name: "Google Greece",
       camera: {
           center: {
               lat: 38.038634694028055,
               lng: 23.802924946201266,
               altitude: 196.45884670344995
           },
           range: 343.57226336076565,
           tilt: 54.97375927639567,
           heading: -33.26775344055724,
       },
       point: { lat: 38.038619, lng: 23.8031622, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/gr.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Germany",
       camera: {
           center: {
               lat: 53.55397683312404,
               lng: 9.986350507286808,
               altitude: 44.83610870143956
           },
           range: 375.3474077822466,
           tilt: 71.35078443829818,
           heading: -160.76930098951416,
       },
       point: { lat: 53.5540227, lng: 9.9863, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/de.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Ireland",
       camera: {
           center: { lat: 53.339816899999995, lng: -6.2362644, altitude: 38.777415761228006 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 53.339816899999995, lng: -6.2362644, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/ie.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Italy",
       camera: {
           center: {
               lat: 45.486361346538224,
               lng: 9.18995496294455,
               altitude: 138.55834058400072
           },
           range: 694.9398023590038,
           tilt: 57.822470255679114,
           heading: 84.10194883488619,
       },
       point: { lat: 45.4863064, lng: 9.1894762, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/it.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Lithuania",
       camera: {
           center: {
               lat: 54.698040606567965,
               lng: 25.30965338542576,
               altitude: 111.80276944294413
           },
           range: 412.5808304977545,
           tilt: 43.50793332082195,
           heading: -29.181098269421028,
       },
       point: { lat: 54.6981204, lng: 25.3098617, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/at.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Netherlands",
       camera: {
           center: {
               lat: 52.33773837150874,
               lng: 4.871754560171063,
               altitude: 53.68063996154723
           },
           range: 473.1982259177312,
           tilt: 56.216523350388634,
           heading: 71.78252318033718,
       },
       point: { lat: 52.337801, lng: 4.872065999999999, altitude: 100 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/nl.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Norway",
       camera: {
           center: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 38.777415761228006 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/no.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Poland",
       camera: {
           center: { lat: 52.22844380000001, lng: 20.9851819, altitude: 38.777415761228006 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 52.22844380000001, lng: 20.9851819, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/pl.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Portugal",
       camera: {
           center: {
               lat: 38.7240122810727,
               lng: -9.150628263172639,
               altitude: 55.299662291551044
           },
           range: 337.7474313328639,
           tilt: 56.79772652682846,
           heading: 176.0722118222208,
       },
       point: { lat: 38.723915999999996, lng: -9.150629, altitude: 35 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/pt.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Romania",
       camera: {
           center: {
               lat: 44.43076650172983,
               lng: 26.109700164718586,
               altitude: 125.57895810814505
           },
           range: 364.25249956711923,
           tilt: 38.517539223834326,
           heading: -38.81294924429363,
       },
       point: { lat: 44.4309897, lng: 26.1095719, altitude: 75 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/ro.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Spain",
       camera: {
           center: {
               lat: 40.450078762608875,
               lng: -3.6930085080020856,
               altitude: 753.6446342341894
           },
           range: 845.7279793010093,
           tilt: 46.752510050599746,
           heading: 4.718779524265234,
       },
       point: { lat: 40.450294199999995, lng: -3.6927915, altitude: 175 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/es.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Sweden",
       camera: {
           center: {
               lat: 59.33313751316038,
               lng: 18.054618219238293,
               altitude: 16.728213706832868
           },
           range: 377.5210725830039,
           tilt: 63.59478230626709,
           heading: 98.53138488367703,
       },
       point: { lat: 59.3332093, lng: 18.0536386, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/se.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Switzerland",
       camera: {
           center: {
               lat: 47.365411056285275,
               lng: 8.525063594405356,
               altitude: 419.2348376754488
           },
           range: 166.74918737631742,
           tilt: 59.31431457129067,
           heading: -32.620415961949206,
       },
       point: { lat: 47.365452, lng: 8.5249253, altitude: 100 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/ch.svg'),
           scale: 1.0,
       },
   }
]

بعد إجراء ذلك، من المفترض أن تظهر صفحة كاملة مثل الصورة المعروضة، ما يسمح للمستخدم بالنقر على أي موقع جغرافي والانتقال إليه والتجوّل فيه ثم الخروج.

&quot;أعمل في مجال الرسوم المتحركة، وأنتقل بين المكاتب في إسبانيا والسويد.

نشكرك على إكمال دورة codelab، ونريد أن نختم هذه الدورة في القسم التالي ونبحث عن أشياء جديدة أخرى لتجربتها.

حلّ القسم

في هذه الخطوة، يتم تقديم الصفحة المكتملة كحلّ للتحقّق من عملية التنفيذ. (في حال النسخ، تأكَّد من استخدام مفتاح واجهة برمجة التطبيقات الخاص بك).

لا تنسَ أيضًا أنّك ستحتاج إلى الحصول على ملف svg للعلم (أو ملفات png حسب اختيارك) وتخزينه في دليل يمكن أن تعثر عليه صفحتك (هنا يتم تخزينه في مجلد images).

<!DOCTYPE html>
<html>

<head>
   <title>Step 9 - More Places!</title>
   <style>
       body {
           height: 100vh;
           margin: 0;
       }
   </style>
</head>

<body>
   <script>
       (g => { var h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window; b = b[c] || (b[c] = {}); var d = b.maps || (b.maps = {}), r = new Set, e = new URLSearchParams, u = () => h || (h = new Promise(async (f, n) => { await (a = m.createElement("script")); e.set("libraries", [...r] + ""); for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]); e.set("callback", c + ".maps." + q); a.src = `https://maps.${c}apis.com/maps/api/js?` + e; d[q] = f; a.onerror = () => h = n(Error(p + " could not load.")); a.nonce = m.querySelector("script[nonce]")?.nonce || ""; m.head.append(a) })); d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)) })({
           key: "<INSERT API KEY>",
           v: "alpha",
           // Use the 'v' parameter to indicate the version to use (weekly, beta, alpha, etc.).
           // Add other bootstrap parameters as needed, using camel case.
       });
   </script>
   <script>
       let map3D = null;

       const base = document.location.href.substr(0, document.location.href.lastIndexOf("/"));

       const europeCamera = {
           center: { lat: 46.717, lng: 7.075, altitude: 2175.130 },
           range: 5814650,
           tilt: 33,
           heading: 4.36,
       };

const officeLocations = [
   {
       name: "Google France",
       details: "8 Rue de Londres, 75009 Paris, France",
       camera: {
           center: { lat: 48.877276, lng: 2.329978, altitude: 48 },
           range: 178,
           tilt: 57.48,
           heading: -17,
       },
       point: { lat: 48.8775183, lng: 2.3299791, altitude: 60 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/fr.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google UK",
       details: "6 Pancras Square, London N1C 4AG, UK",
       camera: {
           center: { lat: 51.5332, lng: -0.1260, altitude: 38.8 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 51.5332, lng: -0.1260, altitude: 75 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/gb.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Belgium",
       details: "Chau. d'Etterbeek 180, 1040 Brussel",
       camera: {
           center: { lat: 50.83930408436509, lng: 4.38052394507952, altitude: 64.38932203802196},
           range: 466.62899893119175,
           tilt: 43.61569474716178,
           heading: 51.805907046332074,
       },
       point: { lat: 50.8392653, lng: 4.3808751, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/be.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Czechia",
       details: "Stroupežnického 3191/17, 150 00 Praha 5-Smíchov",
       camera: {
           center: {
               lat: 50.07004093853976,
               lng: 14.402871475443956,
               altitude: 223.39574818495532
           },
           range: 522.0365799222782,
           tilt: 62.39511972890614,
           heading: -39.150149539328304,
       },
       point: { lat: 50.0703122, lng: 14.402668199999999, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/cz.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Denmark",
       details: "2, Sankt Petri Passage 5, 1165 København",
       camera: {
           center: {
               lat: 55.680359539635866,
               lng: 12.570460204526002,
               altitude: 30.447654757346044
           },
           range: 334.8786935049066,
           tilt: 55.38819319004654,
           heading: 149.63867461295067,
       },
       point: { lat: 55.6804504, lng: 12.570279099999999, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/dk.svg'),
           scale: 1.0,
       },
   },
   ,
   {
       name: "Google Greece",
       details: "Fragkokklisias 6, Athina 151 25",
       camera: {
           center: {
               lat: 38.038634694028055,
               lng: 23.802924946201266,
               altitude: 196.45884670344995
           },
           range: 343.57226336076565,
           tilt: 54.97375927639567,
           heading: -33.26775344055724,
       },
       point: { lat: 38.038619, lng: 23.8031622, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/gr.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Germany",
       details: "ABC-Straße 19, 20354 Hamburg",
       camera: {
           center: {
               lat: 53.55397683312404,
               lng: 9.986350507286808,
               altitude: 44.83610870143956
           },
           range: 375.3474077822466,
           tilt: 71.35078443829818,
           heading: -160.76930098951416,
       },
       point: { lat: 53.5540227, lng: 9.9863, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/de.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Ireland",
       details: "Gordon House, 4 Barrow St, Grand Canal Dock, Dublin 4, D04 V4X7",
       camera: {
           center: { lat: 53.339816899999995, lng: -6.2362644, altitude: 38.777415761228006 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 53.339816899999995, lng: -6.2362644, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/ie.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Italy",
       details: "Isola Building C, Via Federico Confalonieri, 4, 20124 Milano",
       camera: {
           center: {
               lat: 45.486361346538224,
               lng: 9.18995496294455,
               altitude: 138.55834058400072
           },
           range: 694.9398023590038,
           tilt: 57.822470255679114,
           heading: 84.10194883488619,
       },
       point: { lat: 45.4863064, lng: 9.1894762, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/it.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Lithuania",
       details: "Vilnius Tech Park, Antakalnis st. 17, 2nd building, LT-10312, Vilnius",
       camera: {
           center: {
               lat: 54.698040606567965,
               lng: 25.30965338542576,
               altitude: 111.80276944294413
           },
           range: 412.5808304977545,
           tilt: 43.50793332082195,
           heading: -29.181098269421028,
       },
       point: { lat: 54.6981204, lng: 25.3098617, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/at.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Netherlands",
       details: "Claude Debussylaan 34, 1082 MD Amsterdam",
       camera: {
           center: {
               lat: 52.33773837150874,
               lng: 4.871754560171063,
               altitude: 53.68063996154723
           },
           range: 473.1982259177312,
           tilt: 56.216523350388634,
           heading: 71.78252318033718,
       },
       point: { lat: 52.337801, lng: 4.872065999999999, altitude: 100 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/nl.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Norway",
       details: "Bryggegata 6, 0250 Oslo",
       camera: {
           center: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 38.777415761228006 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 59.90991209999999, lng: 10.726020799999999, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/no.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Poland",
       details: "Rondo Daszynskiego 2, 00-843 Warsaw",
       camera: {
           center: { lat: 52.22844380000001, lng: 20.9851819, altitude: 38.777415761228006 },
           range: 500,
           tilt: 56.21672368296945,
           heading: -31.15763027564165,
       },
       point: { lat: 52.22844380000001, lng: 20.9851819, altitude: 25 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/pl.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Portugal",
       details: "R. Duque de Palmela 37 Piso 4, 1250-097 Lisboa",
       camera: {
           center: {
               lat: 38.7240122810727,
               lng: -9.150628263172639,
               altitude: 55.299662291551044
           },
           range: 337.7474313328639,
           tilt: 56.79772652682846,
           heading: 176.0722118222208,
       },
       point: { lat: 38.723915999999996, lng: -9.150629, altitude: 35 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/pt.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Romania",
       details: "Bulevardul Corneliu Coposu 6-8, București 030167",
       camera: {
           center: {
               lat: 44.43076650172983,
               lng: 26.109700164718586,
               altitude: 125.57895810814505
           },
           range: 364.25249956711923,
           tilt: 38.517539223834326,
           heading: -38.81294924429363,
       },
       point: { lat: 44.4309897, lng: 26.1095719, altitude: 75 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/ro.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Spain",
       details: "Torre Picasso, Pl. Pablo Ruiz Picasso, 1, Tetuán, 28020 Madrid",
       camera: {
           center: {
               lat: 40.450078762608875,
               lng: -3.6930085080020856,
               altitude: 753.6446342341894
           },
           range: 845.7279793010093,
           tilt: 46.752510050599746,
           heading: 4.718779524265234,
       },
       point: { lat: 40.450294199999995, lng: -3.6927915, altitude: 175 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/es.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Sweden",
       details: "Kungsbron 2, 111 22 Stockholm",
       camera: {
           center: {
               lat: 59.33313751316038,
               lng: 18.054618219238293,
               altitude: 16.728213706832868
           },
           range: 377.5210725830039,
           tilt: 63.59478230626709,
           heading: 98.53138488367703,
       },
       point: { lat: 59.3332093, lng: 18.0536386, altitude: 50 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/se.svg'),
           scale: 1.0,
       },
   },
   {
       name: "Google Switzerland",
       details: "Brandschenkestrasse 110, 8002 Zürich",
       camera: {
           center: {
               lat: 47.365411056285275,
               lng: 8.525063594405356,
               altitude: 419.2348376754488
           },
           range: 166.74918737631742,
           tilt: 59.31431457129067,
           heading: -32.620415961949206,
       },
       point: { lat: 47.365452, lng: 8.5249253, altitude: 100 },
       pin: {
           background: 'white',
           glyph: new URL(base + '/images/ch.svg'),
           scale: 1.0,
       },
   }
]

       async function init() {
           const { Map3DElement, MapMode, Marker3DInteractiveElement } = await google.maps.importLibrary("maps3d");
           const { PinElement } = await google.maps.importLibrary('marker');

           map3D = new Map3DElement({
               ...europeCamera,
               mode: MapMode.SATELLITE,
           });

           officeLocations.forEach(office => {
               const marker = new Marker3DInteractiveElement({
                   position: office.point,
                   label: office.name,
                   altitudeMode: 'RELATIVE_TO_GROUND',
                   extruded: true,
               });

               marker.addEventListener('gmp-click', (event) => {
                   map3D.flyCameraTo({
                       endCamera: office.camera,
                       durationMillis: 2000,
                   });

                   map3D.addEventListener('gmp-animationend', () => {
                       map3D.flyCameraAround({
                           camera: office.camera,
                           durationMillis: 2000,
                           rounds: 1
                       });

                       map3D.addEventListener('gmp-animationend', () => {
                           map3D.flyCameraTo({
                               endCamera: europeCamera,
                               durationMillis: 2000,
                           });
                       }, { once: true });

                   }, { once: true });

                   event.stopPropagation();
               });

               const markerPin = new PinElement(office.pin);
               marker.append(markerPin);

               map3D.append(marker);
           });
           document.body.append(map3D);
       }
       init();
   </script>
</body>

</html>

12. الخطوات التالية

في هذا الدرس التطبيقي حول الترميز، اطّلعت على أساسيات الإجراءات التي يمكنك تنفيذها باستخدام واجهة برمجة التطبيقات 3D في "خرائط Google". بعد ذلك، حاوِل إضافة بعض هذه العناصر إلى الخريطة:

  • أضِف قائمة منسدلة للسماح باختيار مكتب.
  • استخدِم بعض خيارات تصميم العلامة الأخرى لإبراز المزيد من التوهج.
  • اطّلِع على المكتبات الإضافية المتاحة لواجهة برمجة التطبيقات JavaScript لخرائط Google والتي تتيح ميزات إضافية، مثل استخدام "الأماكن" لعرض تقييم كل مكتب باستخدام رقم تعريفه.

للاطّلاع على مزيد من المعلومات حول الطرق التي يمكنك من خلالها العمل مع "منصّة خرائط Google" والعناصر الثلاثية الأبعاد على الويب، يمكنك الاطّلاع على الروابط التالية: