<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>qlik api - Qlik Sense - Обучение, учебник, онлайн курс</title>
	<atom:link href="https://qliksense.ivan-shamaev.ru/tag/qlik-api/feed/" rel="self" type="application/rss+xml" />
	<link>https://qliksense.ivan-shamaev.ru/tag/qlik-api/</link>
	<description>Qlik Sense на русском языке. Пошаговые уроки для изучения Клик Сенс</description>
	<lastBuildDate>Wed, 02 Dec 2020 20:04:56 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>

<image>
	<url>https://qliksense.ivan-shamaev.ru/wp-content/uploads/2018/07/QlikSense_ICON2-150x150.png</url>
	<title>qlik api - Qlik Sense - Обучение, учебник, онлайн курс</title>
	<link>https://qliksense.ivan-shamaev.ru/tag/qlik-api/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>nebula.js &#8211; Qlik Sense API Javascript библиотека. Примеры</title>
		<link>https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/</link>
					<comments>https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/#respond</comments>
		
		<dc:creator><![CDATA[qliksense-expert]]></dc:creator>
		<pubDate>Wed, 25 Nov 2020 20:03:24 +0000</pubDate>
				<category><![CDATA[Уровень 2]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[nebula.js]]></category>
		<category><![CDATA[qlik api]]></category>
		<category><![CDATA[qlik sense]]></category>
		<category><![CDATA[qlik sense api]]></category>
		<category><![CDATA[Qlik Sense Mashup]]></category>
		<category><![CDATA[qliksense]]></category>
		<guid isPermaLink="false">https://qliksense.ivan-shamaev.ru/?p=2440</guid>

					<description><![CDATA[<p>Введение в nebula.js nebula.js представляет собой набор библиотек JavaScript, визуализаций и интерфейсов командной строки, которые помогают разработчикам создавать и интегрировать визуализации поверх ассоциативного движка Qlik. Коллекция организована в @nebula.jsрамках области в виде пакетов npm. Основной пакет @nebula.js/stardustсодержит API-интерфейсы для интеграции существующих визуализаций с гибридными приложениями, а также API-интерфейсы для создания пользовательских визуализаций. EMBEDDING VISUALIZATIONS.<a class="moretag" href="https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/"> Читать дальше&#8230;</a></p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/">nebula.js &#8211; Qlik Sense API Javascript библиотека. Примеры</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1 id="introduction-to-nebulajs"><span>Введение в nebula.js</span></h1>
<p><code class="language-text">nebula.js</code><span> представляет собой набор библиотек JavaScript, визуализаций и интерфейсов командной строки, которые помогают разработчикам создавать и интегрировать визуализации поверх ассоциативного движка Qlik.</span></p>
<p><span>Коллекция организована в </span><code class="language-text">@nebula.js</code><span>рамках области в виде пакетов npm. Основной пакет </span><code class="language-text">@nebula.js/stardust</code><span>содержит API-интерфейсы для интеграции существующих визуализаций с гибридными приложениями, а также API-интерфейсы для создания пользовательских визуализаций.</span></p>
<h1><strong>EMBEDDING VISUALIZATIONS. ВСТРАИВАНИЕ ВИЗУАЛИЗАЦИЙ</strong></h1>
<h2>Configuration. Конфигурация</h2>
<p><span>Когда вы создаете веб-сайт, будь то сайт всей компании или небольшой личный проект, у вас, скорее всего, есть свои собственные рекомендации по дизайну, шаблоны и требования UX, и вы захотите применить эти рекомендации к тому, что вы с ним интегрируете; диаграммы должны использовать ваши цветовые схемы, шрифты, языковой стандарт и уважать любые ограничения, которые могут быть у вас на интерактивность. Вы также можете контролировать, как загружаются диаграммы и темы, в зависимости от того, подключено ли ваше решение к сети или нет.</span></p>
<p><span>Вы можете управлять большинством из них через </span><code class="language-text">Configuration</code><span>объект.</span></p>
<h3 id="temporary-config">В<span>ременный конфиг</span></h3>
<p><span></span><code class="language-text">Configuration</code><span>Объект является необязательным аргументом , который вы можете предоставить при инстанцировании </span><code class="language-text">embed</code><span>экземпляра:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">import { embed } from '@nebula.js/stardust';

const n = embed(enigmaApp, {
  context: {
    theme: 'dark',
  },
  types: [
    /* types */
  ],
});

n.render(/* chart 1*/);
n.render(/* chart 2*/);</pre>
<h3 id="reusable-config"><span>Многоразовая конфигурация</span></h3>
<p><span>Если вы работаете с несколькими приложениями или хотите иметь несколько разных конфигураций, вам может быть проще сначала создать конфигурации, а затем повторно использовать их.</span></p>
<p><span>Создайте файл, </span><code class="language-text">baseConfig</code><span>который выполняет тяжелую работу по регистрации типов и тем:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const baseConfig = embed.createConfiguration({
  types: [
    /* register type once*/
  ],
  themes: [
    /* register themes once*/
  ],
});</pre>
<p><span>Создайте другую конфигурацию, которая наследуется от </span><code class="language-text">baseConfig</code><span>, примените </span><code class="language-text">'dark'</code><span>тему и установите ограничение, запрещающее выбор:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const noSelectionDark = baseConfig.createConfiguration({
  context: {
    theme: 'dark',
    constraints: { select: true },
  },
});

// render chart with dark theme with no selections allowed
noSelectionDark(enigmaApp).render(/*chart config*/);
noSelectionDark(anotherEnigmaApp).render(/*chart config*/);</pre>
<p><span>Вы также можете напрямую привязать конфигурацию к приложению:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const swedishPink = baseConfig(enigmaApp, {
  context: {
    theme: 'pinkish',
    language: 'sv-SE',
  },
});

swedishPink.render(/* chart config */);</pre>
<h3 id="registering-types"><span>Регистрация типов</span></h3>
<p><span>Перед визуализацией визуализации ее модуль необходимо загрузить и зарегистрировать. Вы можете загрузить необходимые модули из npm:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">$npm install @nebula.js/sn-bar-chart @nebula.js/sn-pie-chart</pre>
<p><span>А потом зарегистрируйте каждого </span><code class="language-text">type</code><span>индивидуально:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import barchart from '@nebula.js/sn-bar-chart';
import piechart from '@nebula.js/sn-pie-chart';

embed.createConfiguration({
  types: [
    {
      name: 'bar',
      load: () =&gt; Promise.resolve(barchart),
    },
    {
      name: 'pie',
      load: () =&gt; Promise.resolve(piechart),
    },
  ],
});</pre>
<h3 id="loading-on-the-fly"><span>Загрузка на лету</span></h3>
<p><span>Если вы точно не знаете, какие типы вам нужны, и не хотите устанавливать все, чтобы уменьшить размер вашего пакета, вы можете загрузить визуализации во время выполнения, используя облегченный загрузчик определений асинхронных модулей, например </span><a href="https://github.com/d3/d3-require"><span>d3-require</span></a><span> .</span></p>
<p><span>Начнем с установки модуля:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">npm install d3-require</pre>
<p><span>а затем настройте его для загрузки модулей из CDN, например </span><code class="language-text">https://unpkg.com</code><span>, а также укажите псевдоним для использования локальной версии </span><code class="language-text">@nebula.js/stardust</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">import { requireFrom } from 'd3-require';
import * as stardust from '@nebula.js/stardust';

const loadSnType = requireFrom((name) =&gt; `https://unpkg.com/@nebula.js/sn-${name}-chart`).alias({
  '@nebula.js/stardust': stardust,
});</pre>
<p><span>Затем вы можете настроить все типы, которые вы ожидаете использовать:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const types = ['bar', 'line', 'pie', 'sankey'].map((t) =&gt; ({
  type: t,
  load: () =&gt; loadSnType(t),
}));
const baseConfig = stardust.embed.createConfiguration({ types });</pre>
<p><span>Тип загружается с удаленного URL-адреса при первом отображении:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">baseConfig(enigmaApp).render({
  type: 'bar',
  fields: ['Product', '=sum(Sales)'],
});</pre>
<h3 id="context"><span>Контекст</span></h3>
<p><span>При настройке конфигурации вы можете применить, </span><code class="language-text">context</code><span>который контролирует язык, тему и ограничения в каждой визуализации, которую вы визуализируете:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">embed.createConfiguration({
  context: {},
});</pre>
<h4 id="constraints"><span>Ограничения</span></h4>
<p><span>Ограничения позволяют указать визуализации на отключение определенных типов взаимодействий и поведения.</span></p>
<p><span>Вы можете применить три различных ограничения:</span></p>
<ul>
<li><code class="language-text">passive</code><span>: отключить такие взаимодействия, как всплывающие подсказки.</span></li>
<li><code class="language-text">active</code><span>: отключение взаимодействий, влияющих на состояние визуального представления, таких как масштабирование, прокрутка и т. д.</span></li>
<li><code class="language-text">select</code><span>: выключить выделение.</span></li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  context: {
    constraints: {
      active: true,
      passive: true,
      select: true,
    },
  },
};</pre>
<p><code class="language-text">stardust</code><span> никоим образом не навязывает эти ограничения, вместо этого разработчик визуализации должен соблюдать и реализовывать их.</span></p>
<h4 id="language"><span>Язык</span></h4>
<p><code class="language-text">stardust</code><span> поддерживает 15 языков:</span></p>
<ul>
<li><code class="language-text">'en-US'</code><span> &#8211; Американский английский</span></li>
<li><code class="language-text">'sv-SE'</code><span> &#8211; шведский</span></li>
<li><code class="language-text">'it-IT'</code><span> &#8211; итальянский</span></li>
<li><code class="language-text">'zh-CN'</code><span> &#8211; Упрощенный китайский</span></li>
<li><code class="language-text">'zh-TW'</code><span> &#8211; Традиционный китайский</span></li>
<li><code class="language-text">'ko-KR'</code><span> &#8211; Корейский язык</span></li>
<li><code class="language-text">'de-DE'</code><span> &#8211; Немецкий</span></li>
<li><code class="language-text">'es-ES'</code><span> &#8211; Испанский</span></li>
<li><code class="language-text">'pt-BR'</code><span> &#8211; Бразильский португальский</span></li>
<li><code class="language-text">'ja-JP'</code><span> &#8211; Японский</span></li>
<li><code class="language-text">'fr-FR'</code><span> &#8211; Французкий язык</span></li>
<li><code class="language-text">'nl-NL'</code><span> &#8211; Голландский</span></li>
<li><code class="language-text">'tr-TR'</code><span> &#8211; Турецкий</span></li>
<li><code class="language-text">'pl-PL'</code><span> &#8211; польский</span></li>
<li><code class="language-text">'ru-RU'</code><span> &#8211; Русский</span></li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  context: {
    language: 'sv-SE',
  },
};</pre>
<h4 id="theme"><span>Тема</span></h4>
<p><span>Из коробки доступны две основные темы: </span><code class="language-text">'light'</code><span>и </span><code class="language-text">'dark'</code><span>.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">{
  context: {
    theme: 'dark',
  }
};</pre>
<p><span>Светлая тема</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs.png"><img fetchpriority="high" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs.png" alt="" width="524" height="436" class="aligncenter size-full wp-image-2442" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs.png 524w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs-300x250.png 300w" sizes="(max-width: 524px) 100vw, 524px" /></a></p>
<p><span>Темная тема</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs.png"><img decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs.png" alt="" width="523" height="434" class="aligncenter size-full wp-image-2443" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs.png 523w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs-300x249.png 300w" sizes="(max-width: 523px) 100vw, 523px" /><span></span></a></p>
<p><span>Вы также можете зарегистрировать собственные темы и применить одну из них в контексте:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  themes: [{
    id: 'pinkish',
    load: () =&gt; Promise.resolve({
      palettes: {
        data: [{
          scale: [
            '#fac6e5',
            '#ff95d6',
            '#e76eb1',
            '#b44772',
          ],
        }]
      }
    })
  }],
  context: {
    theme: 'pinkish'
  }
};</pre>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula.png"><img decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula.png" alt="" width="500" height="359" class="aligncenter size-full wp-image-2445" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula.png 500w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula-300x215.png 300w" sizes="(max-width: 500px) 100vw, 500px" /></a></p>
<h2>Embedding visualizations. Встраивание визуализаций</h2>
<h3 data-testid="docs-header"><span>Встраивание визуализаций</span></h3>
<p><span>Вы можете встроить визуализацию двумя способами:</span></p>
<ol>
<li><span>На лету</span></li>
<li><span>Из существующего объекта</span></li>
</ol>
<p><span>Рендеринг выполняется с использованием </span><code class="language-text">render()</code><span>метода экземпляра, возвращаемого </span><code class="language-text">embed</code><span>функцией, который, как минимум, требует того, в который </span><code class="language-text">HTMLElement</code><span>вы хотите выполнить рендеринг:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { embed } from '@nebula.js/stardust';

const n = embed(enigmaApp);
n.render({
  element,
  // rest of the config
});</pre>
<h3 id="render-on-the-fly"><span>Рендеринг на лету</span></h3>
<p><span>При рендеринге визуализации на лету вам необходимо указать, что </span><code class="language-text">type</code><span> вы хотите визуализировать:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  type: 'barchart',
});</pre>
<p><span>Некоторые визуализации предъявляют минимальные требования к различным свойствам и / или данным, которые необходимо отображать, и в этом случае вы можете увидеть что-то вроде этого:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs.png"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs.png" alt="" width="747" height="489" class="aligncenter size-full wp-image-2447" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs.png 747w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs-300x196.png 300w" sizes="(max-width: 747px) 100vw, 747px" /></a></p>
<p><span>Чтобы предоставить визуализацию исходные данные, добавьте в </span><code class="language-text">fields</code><span>свойство измерения и меры данных :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  type: 'barchart',
  fields: ['Region', '=sum(Sales)'],
});</pre>
<p><span>Вы также можете изменить начальные свойства:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  type: 'barchart',
  fields: ['Product', '=sum(Sales)'],
  properties: {
    title: 'Sales by region',
  },
});</pre>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula.png"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula.png" alt="" width="773" height="529" class="aligncenter size-full wp-image-2448" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula.png 773w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula-300x205.png 300w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula-768x526.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></a></p>
<h2 id="render-from-existing-objects"><span>Рендеринг из существующих объектов</span></h2>
<p><span>Если вы уже создали общий объект в своем приложении и хотите его отобразить, вы можете сделать это, предоставив объекту </span><code class="language-text">id</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  id: '&lt;ObjectID&gt;',
});</pre>
<h2>Current app selections. Выборки текущего приложения</h2>
<p><span>Важной частью Qlik является фильтрация данных с помощью выборок. Большинство диаграмм поддерживают выбор в данных, которые они отображают, которые затем отфильтровывают данные и влияют на другие диаграммы, подключенные к той же модели данных.</span></p>
<h3 id="current-app-selections-bar"><span>Панель выбора текущего приложения</span></h3>
<p><span>На панели выбора текущего приложения отображаются активные в данный момент выборки в указанном приложении. Для рендеринга этого бара вам сначала понадобится </span><code class="language-text">HTMLElement</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">&lt;div class="curr-selections"&gt;&lt;/div&gt;</pre>
<p><span>Затем вы можете </span><code class="language-text">mount</code><span>выбрать пользовательский интерфейс в этом элементе:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const n = embed(enigmaApp);

(await n.selections()).mount(document.querySelector('.curr-selections'));</pre>
<p><span>Без каких-либо выделений должно получиться так:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar.png"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar.png" alt="" width="790" height="57" class="aligncenter size-full wp-image-2449" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar.png 790w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar-300x22.png 300w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar-768x55.png 768w" sizes="(max-width: 790px) 100vw, 790px" /></a></p>
<p><span>Когда вы начинаете применять выборки в различных диаграммах, пользовательский интерфейс обновляется, чтобы отразить текущее состояние:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_update.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_update.gif" alt="" width="792" height="520" class="aligncenter size-full wp-image-2450" /></a></p>
<h3 id="multiple-bars"><span>Несколько баров</span></h3>
<p><span>Если вы подключены к нескольким приложениям, вы можете отобразить текущий выбор в каждом из них, установив панель в разные элементы:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">(await embed(enigmaApp).selections()).mount(document.querySelector('.curr-selections'));

(await embed(anotherApp, { context: { theme: 'dark' } }).selections()).mount(
  document.querySelector('.another-curr-selections')
);</pre>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_multiple_barchart_nebulajs.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_multiple_barchart_nebulajs.gif" alt="" width="1020" height="428" class="aligncenter size-full wp-image-2451" /></a></p>
<h1>DEVELOPING VISUALIZATIONS. РАЗРАБОТКА ВИЗУАЛИЗАЦИЙ</h1>
<h2>Visualization. Визуализация</h2>
<h3 id="whats-a-visualization"><span>Что такое визуализация</span></h3>
<p><span>Визуализация в контексте этого API представляет собой визуальный вывод некоторых базовых данных, хранящихся в ассоциативной модели данных Qlik. Это может быть почти все, что вы хотите, и оно традиционно разработано для отображения данных в форме диаграммы, таблицы, kpi и т. Д.</span></p>
<p><strong>Визуализация состоит из двух основных частей: </strong></p>
<ul>
<li><span>backend <em>Generic Object</em></span><span>, который описывает </span><em><span>свойства</span></em><span> этого визуализация и сохраняется в модели данных, </span></li>
<li><span>и внешний интерфейс визуальной части, которая производит рендеринг <em>layout</em>  </span><span>из <em>Generic Object</em></span><span>.</span></li>
</ul>
<h4 id="definition"><span>Определение</span></h4>
<p><span>Минимальная визуализация, которая не содержит никаких данных и ничего не отображает, выглядит так:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">export default function () {
  return {
    qae: {
      /* */
    },
    component() {},
  };
}</pre>
<p><span>Здесь </span><code class="language-text">component()</code><span>вы визуализируете визуальную часть, а </span><code class="language-text">qae</code><span>здесь вы определяете свойства и данные, обрабатываемые ассоциативным механизмом Qlik (QAE).</span></p>
<h2>Rendering. Рендеринг</h2>
<p><span>В </span><code class="language-text">component</code><span>части определения происходит весь рендеринг, это просто функция, которая ничего не возвращает:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">export default function () {
  return {
    component() {
      // rendering logic goes here
    },
  };
}</pre>
<p><span>Чтобы отрендерить что-то, что вам нужно для доступа к элементу DOM, которому назначена визуализация, вы можете сделать это, импортировав </span><code class="language-text">useElement</code><span> функцию:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useElement } from '@nebula.js/stardust';</pre>
<p><span>Эта функция возвращает простой HTMLElement, который является вашей точкой входа в визуальный мир:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  const element = useElement();
  element.innerHTML = 'Hello!';
}</pre>
<p><code class="language-text">useElement</code><span>&#8211; это одна из многих функций, которые удовлетворяют наиболее распространенные требования при разработке визуализации, они позволяют </span><em><span>подключаться</span></em><span> к ресурсам, предоставляемым обеими </span><code class="language-text">stardust</code><span>сторонами и ассоциативным движком Qlik.</span></p>
<h3 id="hooks">Hooks</h3>
<p><span>Если вы работали с </span><a href="https://reactjs.org/"><span>React,</span></a><span> вы могли узнать это как </span><em><span>хуки</span></em><span> . Хуки &#8211; это концепция, в которой упор делается на многократно используемые составные функции, а не на классические объектно-ориентированные классы и наследование. Хотя реализация полностью настраивается с использованием настраиваемых хуков, концепция и правила очень похожи, настолько, что вы можете прочитать </span><a href="https://reactjs.org/docs/hooks-intro.html"><span>документацию</span></a><span> по <a href="https://reactjs.org/docs/hooks-intro.html">крючкам React,</a> чтобы понять, как использовать собственные хуки stardust.</span></p>
<h4 id="useelement">useElement</h4>
<p><span>Вы уже видели </span><code class="language-text">useElement</code><span>крючок, его единственная цель &#8211; предоставить HTMLElement, к которому вы должны прикрепить свои собственные элементы, чтобы сделать ваш контент видимым, в следующем примере для элемента </span><code class="language-text">innerHTML</code><span>установлено значение </span><code class="language-text">Hello!</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  // get the element
  const element = useElement();
  // set element content
  element.innerHTML = 'Hello!';
}</pre>
<p><span>Однако статическая строка не даст многого, в большинстве случаев вы обновляете контент на основе ввода данных, состояния компонентов и взаимодействия с пользователем.</span></p>
<p><span></span><code class="language-text">component()</code><span>Функция выполняется каждый раз , когда что &#8211; то , что может быть связано с вашими изменениями рендеринга; тема, модель данных, выбор данных, состояние компонента и т. д. Таким образом, добавление и удаление прослушивателей событий, обновление узлов DOM и выборка данных не идеальны и могут быть довольно тяжелыми для производительности, если делать это каждый раз при </span><code class="language-text">component()</code><span>запуске. Вместо этого вы должны выполнять пакетные обновления с </span><code class="language-text">useEffect</code><span>.</span></p>
<h4 id="useeffect"><span>useEffect</span></h4>
<p><code class="language-text">useEffect</code><span>&#8211; это ловушка, которая принимает функцию обратного вызова, которая запускается только при изменении указанного вами значения. Это позволяет не только выполнять пакетные обновления, но и реализовывать собственную форму управления жизненным циклом в вашем компоненте.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useEffect } from '@nebula.js/stardust';
// ...
component() {
  const element = useElement();

  useEffect(() =&gt; {
    // run only once when the component is created
    console.log('created');
  }, []);
}</pre>
<p><span>Добавление слушателей событий к элементу обычно выполняется только при запуске компонента, а затем удаляется при его уничтожении:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  const element = useElement();

  useEffect(() =&gt; {
    const listener = () =&gt; {
      console.log('clicked');
    };

    element.addEventListener('click', listener);

    return () =&gt; {
      // clean-up
      element.removeEventListener('click', listener);
    };
  }, [element]);
}</pre>
<p><span>В предыдущем примере </span><code class="language-text">element</code><span>в качестве второго аргумента предоставляется наблюдаемое значение, поэтому эффект запускается только при </span><code class="language-text">element</code><span>изменении. Однако, поскольку </span><code class="language-text">element</code><span>никогда не изменяется для одного и того же компонента, обратный вызов запускается только один раз при создании компонента. Таким образом </span><code class="language-text">listener</code><span>, экземпляр может быть создан только один раз, и </span><code class="language-text">click</code><span>добавляется только один прослушиватель событий. Обратный вызов также возвращает функцию в конце, это функция очистки, которая выполняется при изменении любого из наблюдаемых значений или при уничтожении компонента. Здесь вы должны очистить все добавленные побочные эффекты, в этом случае прослушиватель событий удаляется, чтобы избежать утечки памяти.</span></p>
<h4 id="usestate"><span>useState</span></h4>
<p><span>Поскольку </span><code class="language-text">component()</code><span>это функция, а не экземпляр класса или объекта, вы не можете использовать его </span><code class="language-text">this</code><span>для хранения значений экземпляра, как в противном случае. Способ хранения состояния </span><code class="language-text">useState</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useState } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const [count, setCount] = useState(0);
    },
  };
}</pre>
<p><code class="language-text">useState</code><span>возвращает кортеж, в котором первый элемент совпадает с начальным значением, указанным в качестве аргумента </span><code class="language-text">useState</code><span>, а второй элемент является функцией установки, с помощью которой вы можете изменить значение.</span></p>
<p><span>В следующем примере </span><code class="language-text">count</code><span>увеличивается на 1, когда пользователь нажимает </span><code class="language-text">element</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  const element = useElement();
  const [count, setCount] = useState(0);

  useEffect(() =&gt; {
    const listener = () =&gt; {
      setCount(count + 1);
    };

    element.addEventListener('click', listener);

    return () =&gt; {
      element.removeEventListener('click', listener);
    };
  }, [element]);
}</pre>
<p><span>Чтобы отобразить обновленное значение, вы можете добавить другое, </span><code class="language-text">useEffect</code><span>которое будет запускаться при </span><code class="language-text">count</code><span>изменении:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const [count, setCount] = useState(0);
useEffect(() =&gt; {
  element.innerHTML = `Count: ${count}`;
}, [count]);</pre>
<h2>Configuring data. Конфигурирование данных</h2>
<p><span>В </span><code class="language-text">qae</code><span>разделе определения вы определяете свойства универсального объекта и форму данных, которые вы ожидаете использовать.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "qae": {
    "properties": {}
  }
}</pre>
<h3 id="generic-object"><span>Общий объект</span></h3>
<p><span>Каждая визуализация связана со всей моделью данных и ассоциативным механизмом Qlik через </span><em><span>универсальный объект</span></em><span> . Это объект JSON, содержащий </span><em><span>свойства, в</span></em><span> результате которых создается </span><em><span>макет</span></em><span> , описывающий состояние внутренней части визуализации.</span></p>
<p><span>Каждый раз, когда кто-то хочет визуализировать вашу визуализацию, в модели данных создается экземпляр универсального объекта. Если у создателя есть необходимые разрешения, он может сохранить и сохранить этот объект в своей модели данных.</span></p>
<h3 id="properties"><span>Свойства</span></h3>
<p><span>Какие свойства вы устанавливаете, полностью зависит от вас, однако это должен быть действительный объект JSON. Большинство свойств &#8211; это просто настройки, которые вы, возможно, захотите сохранить с течением времени. Если вы разрабатываете гистограмму, вы можете сохранить настройку, которая указывает, следует ли ее складывать или какой цвет должны иметь столбцы:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "isStacked": true,
  "barColor": "red"
}</pre>
<p><span>Эти свойства </span><em><span>статичны</span></em><span> , то, что входит, выходит точно так же. Истинная сила универсального объекта &#8211; это </span><em><span>динамические</span></em><span> свойства, которые вы можете установить, что позволяет вам использовать ассоциативный механизм Qlik и получать доступ к данным внутри него.</span></p>
<p><span>Динамические свойства имеют особую структуру, которая позволяет серверной части различать динамические и статические свойства. У них также есть соглашение об именах: все они начинаются с </span><code class="language-text">q</code><span>буквы, за которой следует заглавная буква, что позволяет людям и машинам легко различать два типа свойств.</span></p>
<p><span>Существует множество различных </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas"><span>предопределенных</span></a><span> динамических свойств для различных целей, например, вы можете использовать </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FValueExpression"><span>ValueExpression</span></a><span> для выполнения простых вычислений:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "simpleMath": {
    "qValueExpression": {
      "qExpr": "1+1"
    }
  }
}</pre>
<h4 id="layout">Layout (Макет/Слой)</h4>
<p><span><em>layout </em>из Generic Object является результатом статических и динамических свойств. layout предыдущих свойств выглядит следующим образом:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "isStacked": true,
  "barColor": "red",
  "simpleMath": 2
}</pre>
<p><span>Обратите внимание, что статические свойства остаются точно такими же, в то время как динамическое свойство </span><code class=" language-text">simpleMath</code><span>теперь содержит вычисленный результат ValueExpression.</span></p>
<p><span>Большинство динамических свойств имеют определение ввода и соответствующий вывод макета; а </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FListObjectDef"><span>ListObjectDef</span></a><span> приводит к </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FListObject"><span>ListObject</span></a><span> , а </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FSelectionObjectDef"><span>SelectionObjectDef</span></a><span> результаты в </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FSelectionObject"><span>SelectionObject</span></a><span> , и так далее.</span></p>
<h3 id="data"><span>Данные</span></h3>
<p><span>Наиболее часто используемым определением свойства является </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FHyperCubeDef"><span>HyperCubeDef</span></a><span> , это динамическое свойство, которое предоставляет вам данные из внутренней модели данных. Вы можете разместить это в корне объекта свойств или на более глубоком уровне, и у вас может быть столько, сколько вам нужно:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "qHyperCubeDef": {},
  "anotherOne": {
    "qHyperCubeDef": {},
    "andAThird": {
      "qHyperCubeDef": {}
    }
  }
}</pre>
<p><span>Основными входными данными HyperCubeDef являются </span><em><span>измерения</span></em><span> и </span><em><span>меры</span></em><span> :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "qHyperCubeDef": {
    "qDimensions": [{ "qLibraryId": "hdg534" }],
    "qMeasures": [{ "qLibraryId": "gt5dgd" }]
  }
}</pre>
<p><span>В этом случае измерения и меры жестко запрограммированы на предопределенное значение, которое может существовать в определенной модели данных, что редко бывает тем, что вам нужно. Если вы разрабатываете диаграмму для использования другими с какой-либо моделью данных, которая вам нужна, чтобы можно было добавлять их динамически, вы можете сделать это, указав </span><em><span>целевые объекты данных</span></em><span> .</span></p>
<h4 id="data-targets"><span>Цели данных</span></h4>
<p><span>Целевой объект данных &#8211; это способ определить, где расположены динамические HyperCubeDef в свойствах универсального объекта. Хотя вы </span><code class=" language-text">stardust</code><span>можете просматривать свойства и находить все их использования </span><code class=" language-text">qHyperCubeDef</code><span>, вы можете не захотеть, чтобы все они были динамическими, или вы можете сгенерировать их только для внутреннего использования.</span></p>
<p><span>Вы указываете целевые объекты данных с помощью </span><code class=" language-text">data.targets</code><span>ключа </span><code class=" language-text">qae</code><span>, каждая цель должна иметь </span><code class=" language-text">path</code><span>ключ, который указывает путь JSON к HyperCubeDef из корня объекта свойств:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qae: {
  properties: {
    qHyperCubeDef: {},
    my: {
      nested: {
        qHyperCubeDef: {}
      },
    }
  },
  data: {
    targets: [
      { path: '/qHyperCubeDef' },
      { path: '/my/nested/qHyperCubeDef' },
    ];
  }
}</pre>
<p><span>Вы можете для каждого целевого объекта данных указать дополнительные сведения, такие как максимальное / минимальное количество измерений и мер, и внести изменения при их добавлении.</span></p>
<p><span>Это полезно, когда вы знаете ограничения того, что может отображать диаграмма. Например, круговая диаграмма в основном используется, когда у нее есть ровно одно измерение и одна мера, но вы также можете реализовать поддержку второй меры. Это также избавляет вас от некоторой логики кода, поскольку </span><code class=" language-text">stardust</code><span>не пытается отобразить диаграмму, ограничения которой не были выполнены, а вместо этого показывает, что некоторые поля отсутствуют.</span></p>
<h4 id="field-limitations">Field limitations. <span>Ограничения поля</span></h4>
<p><span>Чтобы указать ограничения для измерений или показателей, добавьте каждый соответствующий тип поля как объект как часть целевого объекта данных:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">targets: [
  {
    path: '/qHyperCubeDef',
    dimensions: {
      min: 1,
      max: 1,
    },
    measures: {
      min: 1,
      max: 2,
    },
  },
];</pre>
<h3 id="field-modifications">Field modifications</h3>
<p><span>Вы также можете изменить добавленное или удаленное поле непосредственно перед тем, как изменение будет применено и отправлено на серверную часть, это полезно для таких вещей, как настройка сортировки при добавлении измерения или добавление дополнительных свойств, которые, как вы знаете, всегда необходимы.</span></p>
<p><span>Если вы, например, хотите убедиться, что нулевые значения подавляются, поскольку это не то, что вы можете визуализировать или представить в хорошем виде, вы можете установить, </span><code class=" language-text">qNullSuppression: true</code><span>когда добавляется измерение:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">dimensions: {
  added(dimension) {
    dimension.qNullSuppression = true;
  }
}</pre>
<h2>Consuming data. Потребление данных</h2>
<h3 id="access-layout">Access layout</h3>
<p><span>Вы можете получить доступ к <em>layout</em> Generic Object</span><span> через набор предопределенных hooks.</span></p>
<h4 id="uselayout">useLayout</h4>
<p><code class="language-text">useLayout</code><span> возвращает </span>evaluated layout свойств Generic Object:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useLayout } from '@nebula.js/stardust';

export default function () {
  return {
    qae: {
      properties: {
        qHyperCubeDef: {},
        simpleMath: {
          qValueExpression: {
            qExpr: '1+1',
          },
        },
      },
    },
    component() {
      const layout = useLayout();
      console.log(layout); // { qHyperCube: {/* HyperCube Layout */}, simpleMath: 2 }
    },
  };
}</pre>
<p><span>Вы должны </span><code class="language-text">useEffect</code><span>при наблюдении изменений на </span><code class="language-text">layout</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const layout = useLayout();

useEffect(() =&gt; {
  // do some heavy update
}, [layout]);</pre>
<h4 id="useapplayout">useAppLayout</h4>
<p><code class="language-text">useAppLayout</code><span>возвращает </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FNxAppLayout"><span>NxAppLayout,</span></a><span> к <a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FNxAppLayout">которому</a> вы в данный момент подключены:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useAppLayout } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const appLayout = useAppLayout();
      console.log(appLayout); // { qTitle: 'App title', qLocaleInfo: {/* */ } }
    },
  };
}</pre>
<p><span>Наиболее распространенный вариант использования макета приложения &#8211; это доступ, </span><code class="language-text">qLocaleInfo</code><span>который содержит сведения о локали, выбранные владельцем приложения и должен использоваться для форматирования чисел.</span></p>
<h3 id="models">Models. <span>Модели</span></h3>
<p><span>Помимо макетов приложения и универсального объекта, у вас есть полный доступ к API, созданным с помощью </span><code class="language-text">enigma.js</code><span>. Эти API-интерфейсы генерируются из схемы JSON-RPC и раскрывают всю мощь Associate Engine Qlik.</span></p>
<h4 id="usemodel"><span>useModel</span></h4>
<p><code class="language-text">useModel</code><span>возвращает сгенерированный API </span><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject"><span>Generic Object</span></a><span> :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const model = useModel();
      model.getInfo().then((info) =&gt; {
        console.log(info);
      });
    },
  };
}</pre>
<p><span>Общие операции в этом API:</span></p>
<ul>
<li><span>делать выбор с помощью </span><code class="language-text">beginSelections</code><span>,  </span><code class="language-text">selectHyperCubeValues</code> и <code class="language-text">endSelections</code></li>
<li><span>получить больше данных с </span><code class="language-text">getHyperCubeData</code></li>
</ul>
<h4 id="useapp"><span>useApp</span></h4>
<p><code class="language-text">useApp</code><span>возвращает сгенерированный API <a href="https://qlik.dev/apis/json-rpc/qix/doc#%23%2Fentries%2FDoc">Doc</a>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useApp } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const app = useApp();
      app.clearAll();
    },
  };
}</pre>
<p><span>Общие операции в этом API:</span></p>
<ul>
<li><span>изменять стек выбора с </span><code class="language-text">clearAll</code><span>,  </span><code class="language-text">back</code><span>,</span><code class="language-text">forward</code></li>
<li><span>создавать и применять закладки с помощью </span><code class="language-text">createBookmark</code> и <code class="language-text">applyBookmark</code></li>
</ul>
<h3 id="useglobal"><span>useGlobal</span></h3>
<p><code class="language-text">useGlobal</code><span>возвращает сгенерированный API </span><a href="https://qlik.dev/apis/json-rpc/qix/global#%23%2Fentries%2FGlobal"><span>Global</span></a><span> :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useGlobal } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const g = useGlobal();
      g.engineVersion().then((v) =&gt; {
        console.log(v);
      });
    },
  };
}</pre>
<p><span>Общие операции в этом API:</span></p>
<ul>
<li><span>получить список приложений с </span><code class="language-text">getDocList</code></li>
</ul>
<h2>HyperCube introduction. Введение в HyperCube</h2>
<p><span>Это </span><code class="language-text">HyperCubeDef</code><span>фундаментальная структура, которую вы настраиваете, прежде чем вам будет предоставлен результат в виде файла </span><code class="language-text">HyperCube</code><span>. Не позволяйте имени пугать вас, хотя оно содержит множество свойств и может быть настроено разными способами, в своей основной форме оно напоминает простую таблицу со строками и столбцами.</span></p>
<h3 id="hypercubedef-configuration"><span>Конфигурация HyperCubeDef</span></h3>
<p><span>Не все свойства одинаково важны, и есть несколько ключевых, о которых нужно помнить при настройке </span><code class="language-text">HyperCubeDef</code><span>.</span></p>
<h4 id="qmode"><span>qMode</span></h4>
<p><span>Хотя вам может не потребоваться </span><code class="language-text">qMode</code><span>явно устанавливать, поскольку по умолчанию используется простейший режим </span><code class="language-text">'S'</code><span>, важно знать, какое влияние он оказывает на структуру данных.</span></p>
<p><code class="language-text">qMode: 'P'</code><span>, или </span><em><span>режим</span></em><span> сводной таблицы, дает вам структуру, подходящую для представления сводных таблиц с группами как в вертикальном, так и в горизонтальном направлениях, а также группы для всех показателей.</span></p>
<p><code class="language-text">qMode: 'T'</code><span>, или </span><em><span>древовидный режим</span></em><span> , дает вам структуру, напоминающую дерево и подходящую для визуализации древовидных визуализаций; древовидная карта, упаковка кругов, солнечные лучи, дендрограмма, решётка и т. д.</span></p>
<p><code class="language-text">qMode: 'S'</code><span>, или </span><em><span>прямой режим</span></em><span> , является самым простым из них и дает вам структуру данных, которая выглядит как простая таблица со строками и столбцами. Для простоты объяснения остальной части гиперкуба можно предположить, что он используется.</span></p>
<h4 id="qdimensions-and-qmeasures"><span>qDimensions и qMeasures</span></h4>
<p><code class="language-text">qDimensions</code><span>и </span><code class="language-text">qMeasures</code><span>являются столбцами вашей «таблицы», нет явного ограничения на их количество, которое вы можете добавить, но часто существует ограничение на количество измерений и мер, которые может обрабатывать определенная диаграмма, и вам нужно сохранить это количество из них в виду, когда вы укажете </span><code class="language-text">qInitialDataFetch</code><span>.</span></p>
<h4 id="qinitialdatafetch"><span>qInitialDataFetch</span></h4>
<p><span>Ассоциативный движок Qlik &#8211; это решение на основе памяти, что означает, что объем данных, которые он может обрабатывать, полностью зависит от ресурсов памяти, к которым у него есть доступ. Таким образом, он может содержать миллиарды значений данных, и поэтому количество строк в гиперкубе также потенциально может достигать миллиардов.</span></p>
<p><span>Чтобы избежать случаев, когда такие огромные объемы данных передаются в интерфейсную часть, гиперкуб по умолчанию вообще не включает никаких строк. Чтобы контролировать это, вы можете установить количество строк и столбцов, которое вы хотите изначально </span><code class="language-text">qInitialDataFetch</code><span>. Это свойство позволяет вам установить </span><em><span>страницы данных, которые</span></em><span> вы хотите извлечь из всего гиперкуба, поэтому вы можете, например, выбрать получение первых 50 строк:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qHyperCubeDef: {
  qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 50, qWidth: 4 }];
}</pre>
<p><span>Если вы думаете о прямой таблице как о сетке, из которой вы хотите извлечь некоторые данные, тогда </span><code class="language-text">qLeft</code><span>и </span><code class="language-text">qTop</code><span>&#8211; это верхний левый угол подмножества, которое вы хотите извлечь, а </span><code class="language-text">qHeight</code><span>и </span><code class="language-text">qWidth</code><span>&#8211; количество строк и столбцов.</span></p>
<p><span>Однако существует максимальный предел в 10 000 ячеек, которые вы можете извлечь за один раз, и это количество вызывает ошибку. Поэтому вам нужно следить за количеством столбцов может потребоваться для обеспечения общей не превышает 10 000. Если вы, например , знаете , что вы никогда не нужно больше , чем 4 колонки, то вы можете установить </span><code class="language-text">qHeight</code><span>на </span><code class="language-text">10000/4</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 2500, qWidth: 4 }];</pre>
<p><span>Первоначальная выборка данных указывает только самую большую возможную часть всего гиперкуба в макете, если в гиперкубе всего 7 строк, вы не получите больше 7. Вы также можете динамически получать больше данных позже.</span></p>
<h3 id="consuming-the-hypercube"><span>Потребление HyperCube</span></h3>
<p><span>Выход, или </span><em><span>компоновка</span></em><span> , из </span><code class=" language-text">HyperCubeDef</code><span>является </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FHyperCube"><span>гиперкубом</span></a><span> . В макете он расположен в том же месте, что и вы определили в своих свойствах, но без </span><code class=" language-text">Def</code><span>, например ввода:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  properties: {
    qHyperCubeDef: {},
    another: {
      one: {
        qHyperCubeDef: {}
      }
    }
  }
}</pre>
<p><span>приводит к выводу:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  layout: {
    qHyperCube: {},
    another: {
      one: {
        qHyperCube: {}
      }
    }
  }
}</pre>
<p><span>Рядом с </span><code class=" language-text">qDimensionInfo</code><span>и </span><code class=" language-text">qMeasureInfo</code><span>свойствами , которые содержат ваши размеры и меры, наиболее важную часть гиперкуба являются </span><em><span>страницы данных</span></em><span> .</span></p>
<h4 id="data-pages"><span>Страницы данных</span></h4>
<p><span>На страницах данных содержатся фактические значения данных гиперкуба, где именно и какая структура они имеют, зависит от </span><code class=" language-text">qMode</code><span>значения, которое вы установили ранее. Для режима </span><code class=" language-text">'S'</code><span>это место </span><code class=" language-text">qDataPages</code><span>, которое, в свою очередь, содержит </span><code class=" language-text">qArea</code><span>и </span><code class=" language-text">qMatrix</code><span>.</span></p>
<p><span>Предполагая, что гиперкуб содержит одно измерение, </span><em><span>название фильма</span></em><span> , и одну меру, </span><em><span>средний рейтинг</span></em><span> , содержимое может выглядеть следующим образом:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qDataPages: [
  {
    qMatrix: [
      [
        // first row
        { qText: '2 Fast 2 Furious', qNum: 'NaN', qElemNumber: 447, qState: 'O' }, // NxCell
        { qText: '6.2', qNum: 6.2, qElemNumber: 0, qState: 'L' },
      ],
      [
        // second
        { qText: '2 Guns', qNum: 'NaN', qElemNumber: 681, qState: 'O' },
        { qText: '6.6', qNum: 6.6, qElemNumber: 0, qState: 'L' },
      ],
    ],
    qArea: { qTop: 0, qLeft: 0, qWidth: 2, qHeight: 2 },
  },
];</pre>
<p><span>Помимо текстовых и числовых значений, каждая </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FNxCell"><span>ячейка NxCell</span></a><span> содержит </span><code class=" language-text">qElemNumber</code><span>свойство, известное как </span><em><span>ранг</span></em><span> . Ранг для ячейки измерения можно рассматривать как свойство, которое однозначно идентифицирует текстовое значение этой ячейки в своем поле во всей модели данных. Вы можете использовать это свойство для обеспечения единообразного поведения во всем приложении, вы можете, например, установить постоянный цвет значений измерения в поле, когда и где бы они ни использовались:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">// color scheme
const colors = ['#26A0A7', '#79D69F', '#F9EC86', '#EC983D'];

const cellColor = colors[cell.qElemNumber % colors.length];</pre>
<p><span>Это свойство также необходимо отслеживать, когда вы хотите сделать выбор в своей диаграмме.</span></p>
<h4 id="getting-more-data"><span>Получение дополнительных данных</span></h4>
<p><span>Из-за ограничения объема данных, которые вы можете получить в исходном макете, могут возникнуть ситуации, когда вам потребуется получить остальные данные, если вы хотите отобразить их больше. Вы можете сделать это с помощью методов, представленных в </span><em><span>модели</span></em><span> универсального объекта. Какой метод использовать, опять же, зависит </span><code class=" language-text">qMode</code><span>от гиперкуба, для </span><code class=" language-text">'S'</code><span>режима это </span><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeData"><span>GetHyperCubeData</span></a><span> .</span></p>
<p><span>При подкачке данных в прямом режиме вы должны начать с просмотра </span><code class=" language-text">qHyperCubeDef.qSize</code><span>свойства, которое содержит информацию о ширине и высоте полного гиперкуба. Исходя из этого, вы можете рассчитать количество страниц, которые вам нужно получить:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel, useLayout, useEffect } from '@nebula.js/stardust';

const NUM_CELLS_PER_PAGE = 10000;
const MAX_PAGES = 10;
// ...
component() {
  const model = useModel();
  const layout = useLayout();

  useEffect(() =&gt; {
    const Y = layout.qHyperCube.qSize.qcy;
    const X = layout.qHyperCube.qSize.qcx;

    const HEIGHT_PER_PAGE = Math.ceil(NUM_CELLS_PER_PAGE / X);
    const NUM_PAGES = Math.floor(MAX_PAGES, Math.ceil(Y / HEIGHT_PER_PAGE));

    const pagesToFetch = [];
    for (let i = 0; i &lt; NUM_PAGES; i++) {
      pagesToFetch.push({ qLeft: 0, qTop: i * HEIGHT_PER_PAGE, qHeight: HEIGHT_PER_PAGE, qWidth: X });
    }

    Promise.all(pagesToFetch.map((page) =&gt; model.getHyperCubeData('/qHyperCubeDef', [page]))).then((pages) =&gt; {
      console.log(pages);
    });
  }, [layout]);

}</pre>
<p><span>Однако вы должны быть </span><strong><span>очень</span></strong><span> осторожны при динамической выборке таких данных, имейте в виду, что размер куба может исчисляться миллионами, выборка такого большого набора данных может занять время и создать очень плохое взаимодействие с пользователем. В предыдущем примере максимальное количество страниц установлено равным 10, так что всего выбирается не более 100 000 значений.</span></p>
<p><span>Вы также можете использовать другие методы, чтобы не получать все данные сразу. </span><em><span>Виртуальная прокрутка</span></em><span> в сочетании с регулированием каждого запроса может значительно повысить производительность. Вам также следует рассмотреть возможность использования сокращенного набора данных, если вам не нужны точные значения:</span></p>
<ul>
<li><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeBinnedData"><span>getHyperCubeBinnedData</span></a><span> связывает точки данных в группы и отлично подходит для тепловых карт и 2D-графиков плотности.</span></li>
<li><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeContinuousData"><span>getHyperCubeContinuousData</span></a><span> уменьшает количество точек в непрерывном измерении и отлично подходит для временных данных.</span></li>
<li><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeReducedData"><span>getHyperCubeReducedData</span></a><span> выполняет некоторую магию вейвлетов и отлично подходит для мини-диаграмм.</span></li>
</ul>
<h2>Selecting data. Выбор данных</h2>
<p><span>Выборка &#8211; это фундаментальная часть ассоциативного механизма Qlik. Все поля и связи между ними содержатся в ассоциативной модели. Когда вы применяете выбор, вы не только применяете фильтр в модели данных, но также демонстрируете связи между вашими источниками данных.</span></p>
<h3 id="applying-selections"><span>Applying selections. </span><span>Применение выделений</span></h3>
<p><span>Выборки можно применять с помощью методов, представленных в модели, возвращенной из </span><code class="language-text">useModel</code><span>хука.</span></p>
<p><span>Поскольку универсальный объект может содержать несколько гиперкубов, вам всегда нужно указать, какой гиперкуб вы хотите выбрать, указав его путь JSON в качестве первого аргумента:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel } from '@nebula.js/stardust';
// ...
component() {
  const model = useModel();

  useEffect(() =&gt; {
    model.selectHyperCubeCells('/qHyperCubeDef', [1], []);
  }, [model])
}</pre>
<h3 id="selection-patterns"><span>Шаблоны выбора. Selection patterns</span></h3>
<p><span>Есть два разных шаблона выбора: мгновенный и модальный.</span></p>
<h4 id="instant-selections"><span>Мгновенный выбор. Instant selections</span></h4>
<p><span>Как видно из названия, этот тип шаблона является немедленным и фильтрует как источник выбора, так и все, на что он влияет.</span></p>
<p><span>В следующем примере, как только значение выбрано на гистограмме, фильтрация применяется мгновенно, и обе диаграммы немедленно обновляются отфильтрованными данными:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_instant_qlik_sense_nebula_js_nebulajs_api.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_instant_qlik_sense_nebula_js_nebulajs_api.gif" alt="" width="912" height="388" class="aligncenter size-full wp-image-2460" /></a></p>
<h4 id="modal-selections"><span>Модальный выбор. Modal selections</span></h4>
<p><span>Когда инициируется модальный выбор, источник выбора входит в форму модального состояния, которое позволяет пользователю изменять выбор до подтверждения изменений.</span></p>
<p><span>В следующем примере пользователь сначала выбирает одно значение на линейчатой ​​диаграмме, после чего другие диаграммы обновляются, как и раньше. Однако гистограмма по-прежнему содержит все доступные данные и позволяет пользователю выбрать другое значение перед подтверждением изменений и обновлением самой гистограммы:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_modal_qlik_sense_nebula_js_nebulajs_api.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_modal_qlik_sense_nebula_js_nebulajs_api.gif" alt="" width="912" height="388" class="aligncenter size-full wp-image-2462" /></a></p>
<p><span>Чтобы реализовать этот тип паттерна, вам необходимо выполнить несколько простых шагов </span><code class=" language-text">useSelections</code><span>в сочетании с </span><code class=" language-text">useModel</code><span>ними:</span></p>
<ol>
<li><span>Войдите в модальное состояние, позвонив </span><code class=" language-text">beginSelections</code><span>.</span></li>
<li><span>Выберите значения.</span></li>
<li><span>Обеспечьте визуальную обратную связь с пользователем о том, что было выбрано, например, изменив прозрачность выбранных значений.</span></li>
<li><span>Следите за выходом из модального состояния, чтобы сбросить визуальную обратную связь.</span></li>
</ol>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel, useSelections, useElement } from '@nebula.js/stardust';
// ...
component() {
  const element = useElement();
  const model = useModel();
  const selections = useSelections();

  useEffect(() =&gt; {
    const clicked = () =&gt; {
      const clickedOnRow = 1;

      // 1. enter modal state if not already in it
      if (!selections.isActive()) {
        selections.beginSelections(['/qHyperCubeDef']);
      }
      // 2. select the clicked row
      model.selectHyperCubeCells('/qHyperCubeDef', [clickedOnRow], []);
    }

    element.addEventListener('click', clicked);
    return () =&gt; {
      element.removeEventListener('click', clicked);
    }
  }, [element, model, selections]);

  useEffect(() =&gt; {
    if (layout.qSelectionInfo.qInSelections) {
      // 3. update with visual feedback on active selections
      // YOUR CODE HERE
    } else {
      // 4. normal update
      // YOUR CODE HERE
    }
  }, [layout]);
}</pre>
<p>&nbsp;</p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/">nebula.js &#8211; Qlik Sense API Javascript библиотека. Примеры</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
