תחילת העבודה עם המחשות חזותיות בהתאמה אישית ב-Looker

‫Looker Visualization API הוא ממשק API של JavaScript שפועל ב-iframe בארגז חול (sandbox) ומתארח באפליקציית Looker.

אתם יכולים להשתמש באותו קוד תצוגה חזותית כדי לספק תצוגה חזותית בכל מקום ב-Looker: חקירות, Looks, מרכזי בקרה, הטמעות או קובצי PDF או תמונות שעברו רינדור.

כל תצוגה חזותית מייצגת תצוגה של שאילתת Looker אחת. ‫Looker מריץ את השאילתה ומעביר את התוצאות לקוד הוויזואליזציה. ‫Looker גם מעביר רכיב DOM שקוד התצוגה החזותית יכול להשתמש בו כדי ליצור את התצוגה.

דרישות

לפני שמתחילים, חשוב לוודא שהדרישות הבאות מתקיימות:

יצירת תצוגה חזותית של Hello World

בקטע הזה מוסבר איך ליצור סקריפט של תצוגה חזותית בהתאמה אישית, שמציג את המאפיין הראשון של שאילתה נתונה.

התוצאה הסופית אמורה להיראות כמו בתמונה הבאה:

הגדרה

יש שתי אפשרויות לפיתוח ולבדיקה של תצוגה חזותית ב-Looker:

אחרי שמגדירים אחת מהאפשרויות האלה, אפשר לפעול לפי הדוגמה שבקטע הזה כדי ליצור hello_world.js.

מבנה הקוד החיוני

כדי לראות את קוד המקור הסופי של הדוגמה הזו, אפשר לעיין במאגר GitHub.

בתיקייה שבה מתבצע האירוח, יוצרים קובץ JavaScript ריק חדש ונותנים לו את השם hello_world.js.

כדי לרשום תצוגה חזותית חדשה בהתאמה אישית ב-Looker, מפעילים את הפונקציה looker.plugins.visualizations.add ומעבירים אליה אובייקט של תצוגה חזותית. האובייקט הזה מכיל את ההגדרה של הוויזואליזציה ואת ממשק המשתמש של ההגדרות שלה.

בדוגמה הבאה מוצג מבנה של תרשים עם כל המאפיינים הנדרשים. הוא מכיל פונקציה create ופונקציה updateAsync שבהן אפשר לכתוב את קוד ההמחשה:

looker.plugins.visualizations.add({
  create: function(element, config) {

  },
  updateAsync: function(data, element, config, queryResponse, details, done) {

  }
})

הקוד הזה הוא קוד תקין של תרשים Looker, אבל הוא עדיין לא מוצג כתרשים ומופיע כתיבה ריקה.

הכנת הבמה

לדוגמה, הפונקציה create כוללת שני ארגומנטים: element ו-config.

‫Looker מספק element, שהוא רכיב DOM שצריך להציב בו את ההמחשה ב-Looker. ‫Looker יוצר את הרכיב הזה ומתאים אותו לגודל הנכון. אתם צריכים להציב את התוכן בתוכו.

הפונקציה create מאפשרת לבצע את ההגדרה הראשונית של הרכיב. בדוגמה הזו, רוצים ליצור תרשים שדומה למבנה ה-HTML הבא:

<style>
  /* custom styles for your chart */
</style>
<div class="hello-world-vis">
  <div>Data Goes Here</div>
</div>

באמצעות JavaScript, אתם יכולים להוסיף רכיבים לרכיב ה-DOM שלכם כדי להתאים למבנה הזה.

בדוגמה הבאה מוצגת הפונקציה הזו עם פרטים נוספים:

create: function(element, config) {

  // Insert a <style> tag with some styles to use later.
  var css = element.innerHTML = `
    <style>
      .hello-world-vis {
        /* Vertical centering */
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: center;
        text-align: center;
      }
    </style>
  `;

  // Create a container element to center the text.
  var container = element.appendChild(document.createElement("div"));
  container.className = "hello-world-vis";

  // Create an element to contain the text.
  this._textElement = container.appendChild(document.createElement("div"));

},

הקוד הזה מוסיף CSS, יוצר את הקונטיינר hello-world-vis ומוסיף את התג div בתוכו.

הקוד גם מקצה את this._textElement למאגר התגים שרוצים להציג. הפעולה הזו נועדה לחסוך לכם זמן, כדי שלא תצטרכו לחפש את הנתונים האלה שוב בהמשך, כשהתרשים יתחיל להופיע.

הפונקציה create היא מקום נוח לבצע בו משימות הגדרה שצריך לבצע רק פעם אחת.

עיבוד

בקטע הזה מוסבר איך להרחיב את השיטה updateAsync כדי להמחיש נתונים באופן חזותי. השיטה הזו נקראת בכל פעם שהתרשים צריך להציג שינויים או כשמתרחש אירוע אחר שעשוי להשפיע על אופן העיבוד של התרשים (לדוגמה, שינוי הגודל של התרשים או שינוי של אפשרות הגדרה).

בדוגמה הזו, צריך למצוא רק את המאפיין הראשון בתא הראשון. אפשר לעשות את זה באמצעות data, שהוא מערך של כל שורה במערך הנתונים, ו-queryResponse, שמכיל מטא-נתונים על השאילתה, כמו שמות וסוגים של שדות.

אפשר גם להשתמש ב-method עזר שנקראת LookerCharts.Utils.htmlForCell כדי לספק את ייצוג ה-HTML המתאים של נקודת הנתונים בתא הזה. השיטה הזו מטפלת באופן אוטומטי ברכיבים כמו קישורי פירוט, עיצוב ופעולות נתונים:

  updateAsync: function(data, element, config, queryResponse, details, done) {

    // Grab the first cell of the data.
    var firstRow = data[0];
    var firstCell = firstRow[queryResponse.fields.dimensions[0].name];

    // Insert the data into the page.
    this._textElement.innerHTML = LookerCharts.Utils.htmlForCell(firstCell);

    // Always call done to indicate a visualization has finished rendering.
    done()
  }

בשלב הזה מסתיימים השלבים הנדרשים כדי ליצור תצוגה חזותית תקינה בהתאמה אישית. עם זאת, חשוב לכלול שיטה לטיפול בשגיאות.

טיפול בשגיאות

הקוד updateAsync שולף את שורת הנתונים הראשונה, אבל יכולות להתרחש שגיאות אם השאילתה לא מחזירה תוצאות או לא מכילה מאפיינים.

בלי טיפול בשגיאות, שגיאת JavaScript מופיעה במסוף הדפדפן, וזה עלול לבלבל את המשתמשים כשהתרשים לא מוצג.

אם יש בעיות בעיבוד של תרשימים, יכולות להופיע בהם הודעות שגיאה בהתאמה אישית. Looker מוסיף שתי פונקציות לאובייקט התצוגה החזותית: addError ו-clearErrors. אתם יכולים להשתמש בפונקציות האלה כדי להציג הודעת שגיאה שתהיה מובנת לכל המשתמשים.

מכיוון שהפונקציות האלה נוספות לאובייקט ההמחשה, הן זמינות מההקשר של הפונקציה updateAsync דרך האובייקט this.

אפשר לשנות את ההתחלה של ה-method‏ updateAsync כדי לזהות מצב שגיאה, להודיע למשתמש על הבעיה ולצאת במקום לנסות לעבד:

  updateAsync: function(data, element, config, queryResponse, details, done) {

    // Clear any errors from previous updates.
    this.clearErrors();

    // Throw some errors and exit if the shape of the data isn't what this chart needs.
    if (queryResponse.fields.dimensions.length == 0) {
      this.addError({title: "No Dimensions", message: "This chart requires dimensions."});
      // Always call done() before exiting early to avoid dashboard exports hanging
      done();
      return;
    }

    if (!data || data.length === 0) {
      this.addError({title: "No Data", message: "The query returned no results."});
      done();
      return;
    }

    // ... the rest of the update code here ...

אם המשתמש יוצר שאילתה שמכילה רק מדדים, מוצגת לו הודעת שגיאה דומה לזו:

עיבוד אסינכרוני וייצוא ל-PDF

בדוגמה הקודמת של "Hello World", הפונקציה done() נקראת מיד אחרי שה-DOM מתעדכן. הגישה הזו מתאימה כי ההגדרה של innerHTML היא סינכרונית.

עם זאת, אם אתם משתמשים בספריות תרשימים כמו D3.js,‏ Chart.js או React, סביר להניח שהעיבוד שלכם הוא אסינכרוני. אם קוראים לפונקציה done() בתחתית הסקריפט, יכול להיות ש-Looker יצלם את המסך לייצוא ל-PDF או ל-PNG לפני שהתרשים יסיים את הציור, ולכן יכול להיות שיוצג משבצת ריקה.

כשמייצאים לוח בקרה מ-Looker, המערכת משתמשת בדפדפן ללא ממשק משתמש ומסתמכת על הקריאה החוזרת (callback) של done() כדי לדעת מתי אפשר לצלם את המסך.

כדי לוודא שהתרשימים ייוצאו בצורה תקינה, צריך לקשר את done() callback לאירוע השלמת הפעולה בספרייה ולהשבית את האנימציות במהלך הייצוא באמצעות הדגל details.print.

בדוגמה הבאה מוסבר איך לטפל בעיבוד אסינכרוני באמצעות D3.js:

  updateAsync: function(data, element, config, queryResponse, details, done) {
    this.clearErrors();

    // Check if Looker is exporting the chart to a PDF/PNG
    const isExport = details && details.print === true;

    // Clear previous elements
    this.svg.selectAll("*").remove();

    const circle = this.svg.append("circle")
      .attr("cx", 50)
      .attr("cy", 50);

    if (isExport) {
      // Instant render for exports. Draw the final state immediately with no transitions
      circle.attr("r", 40);

      // Tell Looker to take the screenshot right now
      done();
    } else {
      // If it's for the browser, start small and animate
      circle.attr("r", 0)
        .transition()
        .duration(1000)
        .attr("r", 40)
        .on("end", () => {
           // Tell Looker the animation is fully complete
           done();
        });
    }
  }

אם אתם משתמשים ב-React, הקפידו להעביר את הקריאה החוזרת done כארגומנט השלישי לפונקציית הרינדור, כדי שמערכת Looker תחכה שרכיבי React יותקנו:

  this.chart = ReactDOM.render(
    <MyCustomChart data={data} />,
    element,
    done // Looker waits for React to finish
  );

הגדרות אישיות

אתם יכולים לאפשר למשתמשים להתאים אישית היבטים של התצוגה החזותית שלהם.

בנוסף למאפיינים האחרים של אובייקט התצוגה החזותית, יש מאפיין שנקרא options.

אפשר להשתמש במאפיין הזה כדי לציין את סוג האפשרויות שהתרשים דורש:

looker.plugins.visualizations.add({
  options: {
    font_size: {
      type: "string",
      label: "Font Size",
      values: [
        {"Large": "large"},
        {"Small": "small"}
      ],
      display: "radio",
      default: "large"
    }
  },
  // ... rest of visualization object ...

בדוגמה הזו נוצרת אפשרות font_size שמוצגת כלחצני בחירה, ומאפשרת למשתמשים לבחור בין גודל גופן "קטן" ל "גדול".

כדי להוסיף את האפשרות לבורר התצוגות החזותיות, צריך לציין את המאפיין options.

כדי להשתמש באפשרות הזו בקוד, צריך לזכור שבשיטה updateAsync יש פרמטר config. הפרמטר הזה מכיל את האפשרויות הבאות:

updateAsync: function(data, element, config, queryResponse, details, done) {

האובייקט config דומה לזה:

{font_size: "large"}

כשמעדכנים את התרשים, אפשר לבדוק את האובייקט הזה ולהגיב בהתאם. כדי להטמיע שינויים בגודל הגופן, מוסיפים את הבדיקה הבאה לסוף שיטת העדכון:

if (config.font_size == "small") {
  this._textElement.className = "hello-world-text-small";
} else {
  this._textElement.className = "hello-world-text-large";
}

צריך גם לעדכן את התג <style> שנוסף ב-method‏ create כדי להגדיר את מחלקות ה-CSS‏ hello-world-text-small ו-hello-world-text-large:

.hello-world-text-large {
  font-size: 72px;
}
.hello-world-text-small {
  font-size: 18px;
}

מכיוון שהפונקציה updateAsync נקראת בכל פעם שההגדרה משתנה, ו-Looker שומר את ההגדרה באופן אוטומטי, זה כל מה שצריך לעשות כדי להגיב להגדרות האישיות.

השלבים הבאים

אפשר לראות את קוד המקור המלא של התצוגה החזותית הזו של Hello World במאגר GitHub של Looker בקוד פתוח.

למידע נוסף על פונקציונליות נוספת, ראו מאמרי העזרה של ה-API להמחשה חזותית.