Введение в nebula.js
nebula.js
представляет собой набор библиотек JavaScript, визуализаций и интерфейсов командной строки, которые помогают разработчикам создавать и интегрировать визуализации поверх ассоциативного движка Qlik.
Коллекция организована в @nebula.js
рамках области в виде пакетов npm. Основной пакет @nebula.js/stardust
содержит API-интерфейсы для интеграции существующих визуализаций с гибридными приложениями, а также API-интерфейсы для создания пользовательских визуализаций.
EMBEDDING VISUALIZATIONS. ВСТРАИВАНИЕ ВИЗУАЛИЗАЦИЙ
Configuration. Конфигурация
Когда вы создаете веб-сайт, будь то сайт всей компании или небольшой личный проект, у вас, скорее всего, есть свои собственные рекомендации по дизайну, шаблоны и требования UX, и вы захотите применить эти рекомендации к тому, что вы с ним интегрируете; диаграммы должны использовать ваши цветовые схемы, шрифты, языковой стандарт и уважать любые ограничения, которые могут быть у вас на интерактивность. Вы также можете контролировать, как загружаются диаграммы и темы, в зависимости от того, подключено ли ваше решение к сети или нет.
Вы можете управлять большинством из них через Configuration
объект.
Временный конфиг
Configuration
Объект является необязательным аргументом , который вы можете предоставить при инстанцировании embed
экземпляра:
import { embed } from '@nebula.js/stardust'; const n = embed(enigmaApp, { context: { theme: 'dark', }, types: [ /* types */ ], }); n.render(/* chart 1*/); n.render(/* chart 2*/);
Многоразовая конфигурация
Если вы работаете с несколькими приложениями или хотите иметь несколько разных конфигураций, вам может быть проще сначала создать конфигурации, а затем повторно использовать их.
Создайте файл, baseConfig
который выполняет тяжелую работу по регистрации типов и тем:
const baseConfig = embed.createConfiguration({ types: [ /* register type once*/ ], themes: [ /* register themes once*/ ], });
Создайте другую конфигурацию, которая наследуется от baseConfig
, примените 'dark'
тему и установите ограничение, запрещающее выбор:
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*/);
Вы также можете напрямую привязать конфигурацию к приложению:
const swedishPink = baseConfig(enigmaApp, { context: { theme: 'pinkish', language: 'sv-SE', }, }); swedishPink.render(/* chart config */);
Регистрация типов
Перед визуализацией визуализации ее модуль необходимо загрузить и зарегистрировать. Вы можете загрузить необходимые модули из npm:
$npm install @nebula.js/sn-bar-chart @nebula.js/sn-pie-chart
А потом зарегистрируйте каждого type
индивидуально:
import barchart from '@nebula.js/sn-bar-chart'; import piechart from '@nebula.js/sn-pie-chart'; embed.createConfiguration({ types: [ { name: 'bar', load: () => Promise.resolve(barchart), }, { name: 'pie', load: () => Promise.resolve(piechart), }, ], });
Загрузка на лету
Если вы точно не знаете, какие типы вам нужны, и не хотите устанавливать все, чтобы уменьшить размер вашего пакета, вы можете загрузить визуализации во время выполнения, используя облегченный загрузчик определений асинхронных модулей, например d3-require .
Начнем с установки модуля:
npm install d3-require
а затем настройте его для загрузки модулей из CDN, например https://unpkg.com
, а также укажите псевдоним для использования локальной версии @nebula.js/stardust
:
import { requireFrom } from 'd3-require'; import * as stardust from '@nebula.js/stardust'; const loadSnType = requireFrom((name) => `https://unpkg.com/@nebula.js/sn-${name}-chart`).alias({ '@nebula.js/stardust': stardust, });
Затем вы можете настроить все типы, которые вы ожидаете использовать:
const types = ['bar', 'line', 'pie', 'sankey'].map((t) => ({ type: t, load: () => loadSnType(t), })); const baseConfig = stardust.embed.createConfiguration({ types });
Тип загружается с удаленного URL-адреса при первом отображении:
baseConfig(enigmaApp).render({ type: 'bar', fields: ['Product', '=sum(Sales)'], });
Контекст
При настройке конфигурации вы можете применить, context
который контролирует язык, тему и ограничения в каждой визуализации, которую вы визуализируете:
embed.createConfiguration({ context: {}, });
Ограничения
Ограничения позволяют указать визуализации на отключение определенных типов взаимодействий и поведения.
Вы можете применить три различных ограничения:
passive
: отключить такие взаимодействия, как всплывающие подсказки.active
: отключение взаимодействий, влияющих на состояние визуального представления, таких как масштабирование, прокрутка и т. д.select
: выключить выделение.
{ context: { constraints: { active: true, passive: true, select: true, }, }, };
stardust
никоим образом не навязывает эти ограничения, вместо этого разработчик визуализации должен соблюдать и реализовывать их.
Язык
stardust
поддерживает 15 языков:
'en-US'
– Американский английский'sv-SE'
– шведский'it-IT'
– итальянский'zh-CN'
– Упрощенный китайский'zh-TW'
– Традиционный китайский'ko-KR'
– Корейский язык'de-DE'
– Немецкий'es-ES'
– Испанский'pt-BR'
– Бразильский португальский'ja-JP'
– Японский'fr-FR'
– Французкий язык'nl-NL'
– Голландский'tr-TR'
– Турецкий'pl-PL'
– польский'ru-RU'
– Русский
{ context: { language: 'sv-SE', }, };
Тема
Из коробки доступны две основные темы: 'light'
и 'dark'
.
{ context: { theme: 'dark', } };
Светлая тема
Темная тема
Вы также можете зарегистрировать собственные темы и применить одну из них в контексте:
{ themes: [{ id: 'pinkish', load: () => Promise.resolve({ palettes: { data: [{ scale: [ '#fac6e5', '#ff95d6', '#e76eb1', '#b44772', ], }] } }) }], context: { theme: 'pinkish' } };
Embedding visualizations. Встраивание визуализаций
Встраивание визуализаций
Вы можете встроить визуализацию двумя способами:
- На лету
- Из существующего объекта
Рендеринг выполняется с использованием render()
метода экземпляра, возвращаемого embed
функцией, который, как минимум, требует того, в который HTMLElement
вы хотите выполнить рендеринг:
import { embed } from '@nebula.js/stardust'; const n = embed(enigmaApp); n.render({ element, // rest of the config });
Рендеринг на лету
При рендеринге визуализации на лету вам необходимо указать, что type
вы хотите визуализировать:
n.render({ element, type: 'barchart', });
Некоторые визуализации предъявляют минимальные требования к различным свойствам и / или данным, которые необходимо отображать, и в этом случае вы можете увидеть что-то вроде этого:
Чтобы предоставить визуализацию исходные данные, добавьте в fields
свойство измерения и меры данных :
n.render({ element, type: 'barchart', fields: ['Region', '=sum(Sales)'], });
Вы также можете изменить начальные свойства:
n.render({ element, type: 'barchart', fields: ['Product', '=sum(Sales)'], properties: { title: 'Sales by region', }, });
Рендеринг из существующих объектов
Если вы уже создали общий объект в своем приложении и хотите его отобразить, вы можете сделать это, предоставив объекту id
:
n.render({ element, id: '<ObjectID>', });
Current app selections. Выборки текущего приложения
Важной частью Qlik является фильтрация данных с помощью выборок. Большинство диаграмм поддерживают выбор в данных, которые они отображают, которые затем отфильтровывают данные и влияют на другие диаграммы, подключенные к той же модели данных.
Панель выбора текущего приложения
На панели выбора текущего приложения отображаются активные в данный момент выборки в указанном приложении. Для рендеринга этого бара вам сначала понадобится HTMLElement
:
<div class="curr-selections"></div>
Затем вы можете mount
выбрать пользовательский интерфейс в этом элементе:
const n = embed(enigmaApp); (await n.selections()).mount(document.querySelector('.curr-selections'));
Без каких-либо выделений должно получиться так:
Когда вы начинаете применять выборки в различных диаграммах, пользовательский интерфейс обновляется, чтобы отразить текущее состояние:
Несколько баров
Если вы подключены к нескольким приложениям, вы можете отобразить текущий выбор в каждом из них, установив панель в разные элементы:
(await embed(enigmaApp).selections()).mount(document.querySelector('.curr-selections')); (await embed(anotherApp, { context: { theme: 'dark' } }).selections()).mount( document.querySelector('.another-curr-selections') );
DEVELOPING VISUALIZATIONS. РАЗРАБОТКА ВИЗУАЛИЗАЦИЙ
Visualization. Визуализация
Что такое визуализация
Визуализация в контексте этого API представляет собой визуальный вывод некоторых базовых данных, хранящихся в ассоциативной модели данных Qlik. Это может быть почти все, что вы хотите, и оно традиционно разработано для отображения данных в форме диаграммы, таблицы, kpi и т. Д.
Визуализация состоит из двух основных частей:
- backend Generic Object, который описывает свойства этого визуализация и сохраняется в модели данных,
- и внешний интерфейс визуальной части, которая производит рендеринг layout из Generic Object.
Определение
Минимальная визуализация, которая не содержит никаких данных и ничего не отображает, выглядит так:
export default function () { return { qae: { /* */ }, component() {}, }; }
Здесь component()
вы визуализируете визуальную часть, а qae
здесь вы определяете свойства и данные, обрабатываемые ассоциативным механизмом Qlik (QAE).
Rendering. Рендеринг
В component
части определения происходит весь рендеринг, это просто функция, которая ничего не возвращает:
export default function () { return { component() { // rendering logic goes here }, }; }
Чтобы отрендерить что-то, что вам нужно для доступа к элементу DOM, которому назначена визуализация, вы можете сделать это, импортировав useElement
функцию:
import { useElement } from '@nebula.js/stardust';
Эта функция возвращает простой HTMLElement, который является вашей точкой входа в визуальный мир:
component() { const element = useElement(); element.innerHTML = 'Hello!'; }
useElement
– это одна из многих функций, которые удовлетворяют наиболее распространенные требования при разработке визуализации, они позволяют подключаться к ресурсам, предоставляемым обеими stardust
сторонами и ассоциативным движком Qlik.
Hooks
Если вы работали с React, вы могли узнать это как хуки . Хуки – это концепция, в которой упор делается на многократно используемые составные функции, а не на классические объектно-ориентированные классы и наследование. Хотя реализация полностью настраивается с использованием настраиваемых хуков, концепция и правила очень похожи, настолько, что вы можете прочитать документацию по крючкам React, чтобы понять, как использовать собственные хуки stardust.
useElement
Вы уже видели useElement
крючок, его единственная цель – предоставить HTMLElement, к которому вы должны прикрепить свои собственные элементы, чтобы сделать ваш контент видимым, в следующем примере для элемента innerHTML
установлено значение Hello!
:
component() { // get the element const element = useElement(); // set element content element.innerHTML = 'Hello!'; }
Однако статическая строка не даст многого, в большинстве случаев вы обновляете контент на основе ввода данных, состояния компонентов и взаимодействия с пользователем.
component()
Функция выполняется каждый раз , когда что – то , что может быть связано с вашими изменениями рендеринга; тема, модель данных, выбор данных, состояние компонента и т. д. Таким образом, добавление и удаление прослушивателей событий, обновление узлов DOM и выборка данных не идеальны и могут быть довольно тяжелыми для производительности, если делать это каждый раз при component()
запуске. Вместо этого вы должны выполнять пакетные обновления с useEffect
.
useEffect
useEffect
– это ловушка, которая принимает функцию обратного вызова, которая запускается только при изменении указанного вами значения. Это позволяет не только выполнять пакетные обновления, но и реализовывать собственную форму управления жизненным циклом в вашем компоненте.
import { useEffect } from '@nebula.js/stardust'; // ... component() { const element = useElement(); useEffect(() => { // run only once when the component is created console.log('created'); }, []); }
Добавление слушателей событий к элементу обычно выполняется только при запуске компонента, а затем удаляется при его уничтожении:
component() { const element = useElement(); useEffect(() => { const listener = () => { console.log('clicked'); }; element.addEventListener('click', listener); return () => { // clean-up element.removeEventListener('click', listener); }; }, [element]); }
В предыдущем примере element
в качестве второго аргумента предоставляется наблюдаемое значение, поэтому эффект запускается только при element
изменении. Однако, поскольку element
никогда не изменяется для одного и того же компонента, обратный вызов запускается только один раз при создании компонента. Таким образом listener
, экземпляр может быть создан только один раз, и click
добавляется только один прослушиватель событий. Обратный вызов также возвращает функцию в конце, это функция очистки, которая выполняется при изменении любого из наблюдаемых значений или при уничтожении компонента. Здесь вы должны очистить все добавленные побочные эффекты, в этом случае прослушиватель событий удаляется, чтобы избежать утечки памяти.
useState
Поскольку component()
это функция, а не экземпляр класса или объекта, вы не можете использовать его this
для хранения значений экземпляра, как в противном случае. Способ хранения состояния useState
:
import { useState } from '@nebula.js/stardust'; export default function () { return { component() { const [count, setCount] = useState(0); }, }; }
useState
возвращает кортеж, в котором первый элемент совпадает с начальным значением, указанным в качестве аргумента useState
, а второй элемент является функцией установки, с помощью которой вы можете изменить значение.
В следующем примере count
увеличивается на 1, когда пользователь нажимает element
:
component() { const element = useElement(); const [count, setCount] = useState(0); useEffect(() => { const listener = () => { setCount(count + 1); }; element.addEventListener('click', listener); return () => { element.removeEventListener('click', listener); }; }, [element]); }
Чтобы отобразить обновленное значение, вы можете добавить другое, useEffect
которое будет запускаться при count
изменении:
const [count, setCount] = useState(0); useEffect(() => { element.innerHTML = `Count: ${count}`; }, [count]);
Configuring data. Конфигурирование данных
В qae
разделе определения вы определяете свойства универсального объекта и форму данных, которые вы ожидаете использовать.
{ "qae": { "properties": {} } }
Общий объект
Каждая визуализация связана со всей моделью данных и ассоциативным механизмом Qlik через универсальный объект . Это объект JSON, содержащий свойства, в результате которых создается макет , описывающий состояние внутренней части визуализации.
Каждый раз, когда кто-то хочет визуализировать вашу визуализацию, в модели данных создается экземпляр универсального объекта. Если у создателя есть необходимые разрешения, он может сохранить и сохранить этот объект в своей модели данных.
Свойства
Какие свойства вы устанавливаете, полностью зависит от вас, однако это должен быть действительный объект JSON. Большинство свойств – это просто настройки, которые вы, возможно, захотите сохранить с течением времени. Если вы разрабатываете гистограмму, вы можете сохранить настройку, которая указывает, следует ли ее складывать или какой цвет должны иметь столбцы:
{ "isStacked": true, "barColor": "red" }
Эти свойства статичны , то, что входит, выходит точно так же. Истинная сила универсального объекта – это динамические свойства, которые вы можете установить, что позволяет вам использовать ассоциативный механизм Qlik и получать доступ к данным внутри него.
Динамические свойства имеют особую структуру, которая позволяет серверной части различать динамические и статические свойства. У них также есть соглашение об именах: все они начинаются с q
буквы, за которой следует заглавная буква, что позволяет людям и машинам легко различать два типа свойств.
Существует множество различных предопределенных динамических свойств для различных целей, например, вы можете использовать ValueExpression для выполнения простых вычислений:
{ "simpleMath": { "qValueExpression": { "qExpr": "1+1" } } }
Layout (Макет/Слой)
layout из Generic Object является результатом статических и динамических свойств. layout предыдущих свойств выглядит следующим образом:
{ "isStacked": true, "barColor": "red", "simpleMath": 2 }
Обратите внимание, что статические свойства остаются точно такими же, в то время как динамическое свойство simpleMath
теперь содержит вычисленный результат ValueExpression.
Большинство динамических свойств имеют определение ввода и соответствующий вывод макета; а ListObjectDef приводит к ListObject , а SelectionObjectDef результаты в SelectionObject , и так далее.
Данные
Наиболее часто используемым определением свойства является HyperCubeDef , это динамическое свойство, которое предоставляет вам данные из внутренней модели данных. Вы можете разместить это в корне объекта свойств или на более глубоком уровне, и у вас может быть столько, сколько вам нужно:
{ "qHyperCubeDef": {}, "anotherOne": { "qHyperCubeDef": {}, "andAThird": { "qHyperCubeDef": {} } } }
Основными входными данными HyperCubeDef являются измерения и меры :
{ "qHyperCubeDef": { "qDimensions": [{ "qLibraryId": "hdg534" }], "qMeasures": [{ "qLibraryId": "gt5dgd" }] } }
В этом случае измерения и меры жестко запрограммированы на предопределенное значение, которое может существовать в определенной модели данных, что редко бывает тем, что вам нужно. Если вы разрабатываете диаграмму для использования другими с какой-либо моделью данных, которая вам нужна, чтобы можно было добавлять их динамически, вы можете сделать это, указав целевые объекты данных .
Цели данных
Целевой объект данных – это способ определить, где расположены динамические HyperCubeDef в свойствах универсального объекта. Хотя вы stardust
можете просматривать свойства и находить все их использования qHyperCubeDef
, вы можете не захотеть, чтобы все они были динамическими, или вы можете сгенерировать их только для внутреннего использования.
Вы указываете целевые объекты данных с помощью data.targets
ключа qae
, каждая цель должна иметь path
ключ, который указывает путь JSON к HyperCubeDef из корня объекта свойств:
qae: { properties: { qHyperCubeDef: {}, my: { nested: { qHyperCubeDef: {} }, } }, data: { targets: [ { path: '/qHyperCubeDef' }, { path: '/my/nested/qHyperCubeDef' }, ]; } }
Вы можете для каждого целевого объекта данных указать дополнительные сведения, такие как максимальное / минимальное количество измерений и мер, и внести изменения при их добавлении.
Это полезно, когда вы знаете ограничения того, что может отображать диаграмма. Например, круговая диаграмма в основном используется, когда у нее есть ровно одно измерение и одна мера, но вы также можете реализовать поддержку второй меры. Это также избавляет вас от некоторой логики кода, поскольку stardust
не пытается отобразить диаграмму, ограничения которой не были выполнены, а вместо этого показывает, что некоторые поля отсутствуют.
Field limitations. Ограничения поля
Чтобы указать ограничения для измерений или показателей, добавьте каждый соответствующий тип поля как объект как часть целевого объекта данных:
targets: [ { path: '/qHyperCubeDef', dimensions: { min: 1, max: 1, }, measures: { min: 1, max: 2, }, }, ];
Field modifications
Вы также можете изменить добавленное или удаленное поле непосредственно перед тем, как изменение будет применено и отправлено на серверную часть, это полезно для таких вещей, как настройка сортировки при добавлении измерения или добавление дополнительных свойств, которые, как вы знаете, всегда необходимы.
Если вы, например, хотите убедиться, что нулевые значения подавляются, поскольку это не то, что вы можете визуализировать или представить в хорошем виде, вы можете установить, qNullSuppression: true
когда добавляется измерение:
dimensions: { added(dimension) { dimension.qNullSuppression = true; } }
Consuming data. Потребление данных
Access layout
Вы можете получить доступ к layout Generic Object через набор предопределенных hooks.
useLayout
useLayout
возвращает evaluated layout свойств Generic Object:
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 } }, }; }
Вы должны useEffect
при наблюдении изменений на layout
:
const layout = useLayout(); useEffect(() => { // do some heavy update }, [layout]);
useAppLayout
useAppLayout
возвращает NxAppLayout, к которому вы в данный момент подключены:
import { useAppLayout } from '@nebula.js/stardust'; export default function () { return { component() { const appLayout = useAppLayout(); console.log(appLayout); // { qTitle: 'App title', qLocaleInfo: {/* */ } } }, }; }
Наиболее распространенный вариант использования макета приложения – это доступ, qLocaleInfo
который содержит сведения о локали, выбранные владельцем приложения и должен использоваться для форматирования чисел.
Models. Модели
Помимо макетов приложения и универсального объекта, у вас есть полный доступ к API, созданным с помощью enigma.js
. Эти API-интерфейсы генерируются из схемы JSON-RPC и раскрывают всю мощь Associate Engine Qlik.
useModel
useModel
возвращает сгенерированный API Generic Object :
import { useModel } from '@nebula.js/stardust'; export default function () { return { component() { const model = useModel(); model.getInfo().then((info) => { console.log(info); }); }, }; }
Общие операции в этом API:
- делать выбор с помощью
beginSelections
,selectHyperCubeValues
иendSelections
- получить больше данных с
getHyperCubeData
useApp
useApp
возвращает сгенерированный API Doc:
import { useApp } from '@nebula.js/stardust'; export default function () { return { component() { const app = useApp(); app.clearAll(); }, }; }
Общие операции в этом API:
- изменять стек выбора с
clearAll
,back
,forward
- создавать и применять закладки с помощью
createBookmark
иapplyBookmark
useGlobal
useGlobal
возвращает сгенерированный API Global :
import { useGlobal } from '@nebula.js/stardust'; export default function () { return { component() { const g = useGlobal(); g.engineVersion().then((v) => { console.log(v); }); }, }; }
Общие операции в этом API:
- получить список приложений с
getDocList
HyperCube introduction. Введение в HyperCube
Это HyperCubeDef
фундаментальная структура, которую вы настраиваете, прежде чем вам будет предоставлен результат в виде файла HyperCube
. Не позволяйте имени пугать вас, хотя оно содержит множество свойств и может быть настроено разными способами, в своей основной форме оно напоминает простую таблицу со строками и столбцами.
Конфигурация HyperCubeDef
Не все свойства одинаково важны, и есть несколько ключевых, о которых нужно помнить при настройке HyperCubeDef
.
qMode
Хотя вам может не потребоваться qMode
явно устанавливать, поскольку по умолчанию используется простейший режим 'S'
, важно знать, какое влияние он оказывает на структуру данных.
qMode: 'P'
, или режим сводной таблицы, дает вам структуру, подходящую для представления сводных таблиц с группами как в вертикальном, так и в горизонтальном направлениях, а также группы для всех показателей.
qMode: 'T'
, или древовидный режим , дает вам структуру, напоминающую дерево и подходящую для визуализации древовидных визуализаций; древовидная карта, упаковка кругов, солнечные лучи, дендрограмма, решётка и т. д.
qMode: 'S'
, или прямой режим , является самым простым из них и дает вам структуру данных, которая выглядит как простая таблица со строками и столбцами. Для простоты объяснения остальной части гиперкуба можно предположить, что он используется.
qDimensions и qMeasures
qDimensions
и qMeasures
являются столбцами вашей «таблицы», нет явного ограничения на их количество, которое вы можете добавить, но часто существует ограничение на количество измерений и мер, которые может обрабатывать определенная диаграмма, и вам нужно сохранить это количество из них в виду, когда вы укажете qInitialDataFetch
.
qInitialDataFetch
Ассоциативный движок Qlik – это решение на основе памяти, что означает, что объем данных, которые он может обрабатывать, полностью зависит от ресурсов памяти, к которым у него есть доступ. Таким образом, он может содержать миллиарды значений данных, и поэтому количество строк в гиперкубе также потенциально может достигать миллиардов.
Чтобы избежать случаев, когда такие огромные объемы данных передаются в интерфейсную часть, гиперкуб по умолчанию вообще не включает никаких строк. Чтобы контролировать это, вы можете установить количество строк и столбцов, которое вы хотите изначально qInitialDataFetch
. Это свойство позволяет вам установить страницы данных, которые вы хотите извлечь из всего гиперкуба, поэтому вы можете, например, выбрать получение первых 50 строк:
qHyperCubeDef: { qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 50, qWidth: 4 }]; }
Если вы думаете о прямой таблице как о сетке, из которой вы хотите извлечь некоторые данные, тогда qLeft
и qTop
– это верхний левый угол подмножества, которое вы хотите извлечь, а qHeight
и qWidth
– количество строк и столбцов.
Однако существует максимальный предел в 10 000 ячеек, которые вы можете извлечь за один раз, и это количество вызывает ошибку. Поэтому вам нужно следить за количеством столбцов может потребоваться для обеспечения общей не превышает 10 000. Если вы, например , знаете , что вы никогда не нужно больше , чем 4 колонки, то вы можете установить qHeight
на 10000/4
:
qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 2500, qWidth: 4 }];
Первоначальная выборка данных указывает только самую большую возможную часть всего гиперкуба в макете, если в гиперкубе всего 7 строк, вы не получите больше 7. Вы также можете динамически получать больше данных позже.
Потребление HyperCube
Выход, или компоновка , из HyperCubeDef
является гиперкубом . В макете он расположен в том же месте, что и вы определили в своих свойствах, но без Def
, например ввода:
{ properties: { qHyperCubeDef: {}, another: { one: { qHyperCubeDef: {} } } } }
приводит к выводу:
{ layout: { qHyperCube: {}, another: { one: { qHyperCube: {} } } } }
Рядом с qDimensionInfo
и qMeasureInfo
свойствами , которые содержат ваши размеры и меры, наиболее важную часть гиперкуба являются страницы данных .
Страницы данных
На страницах данных содержатся фактические значения данных гиперкуба, где именно и какая структура они имеют, зависит от qMode
значения, которое вы установили ранее. Для режима 'S'
это место qDataPages
, которое, в свою очередь, содержит qArea
и qMatrix
.
Предполагая, что гиперкуб содержит одно измерение, название фильма , и одну меру, средний рейтинг , содержимое может выглядеть следующим образом:
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 }, }, ];
Помимо текстовых и числовых значений, каждая ячейка NxCell содержит qElemNumber
свойство, известное как ранг . Ранг для ячейки измерения можно рассматривать как свойство, которое однозначно идентифицирует текстовое значение этой ячейки в своем поле во всей модели данных. Вы можете использовать это свойство для обеспечения единообразного поведения во всем приложении, вы можете, например, установить постоянный цвет значений измерения в поле, когда и где бы они ни использовались:
// color scheme const colors = ['#26A0A7', '#79D69F', '#F9EC86', '#EC983D']; const cellColor = colors[cell.qElemNumber % colors.length];
Это свойство также необходимо отслеживать, когда вы хотите сделать выбор в своей диаграмме.
Получение дополнительных данных
Из-за ограничения объема данных, которые вы можете получить в исходном макете, могут возникнуть ситуации, когда вам потребуется получить остальные данные, если вы хотите отобразить их больше. Вы можете сделать это с помощью методов, представленных в модели универсального объекта. Какой метод использовать, опять же, зависит qMode
от гиперкуба, для 'S'
режима это GetHyperCubeData .
При подкачке данных в прямом режиме вы должны начать с просмотра qHyperCubeDef.qSize
свойства, которое содержит информацию о ширине и высоте полного гиперкуба. Исходя из этого, вы можете рассчитать количество страниц, которые вам нужно получить:
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(() => { 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 < NUM_PAGES; i++) { pagesToFetch.push({ qLeft: 0, qTop: i * HEIGHT_PER_PAGE, qHeight: HEIGHT_PER_PAGE, qWidth: X }); } Promise.all(pagesToFetch.map((page) => model.getHyperCubeData('/qHyperCubeDef', [page]))).then((pages) => { console.log(pages); }); }, [layout]); }
Однако вы должны быть очень осторожны при динамической выборке таких данных, имейте в виду, что размер куба может исчисляться миллионами, выборка такого большого набора данных может занять время и создать очень плохое взаимодействие с пользователем. В предыдущем примере максимальное количество страниц установлено равным 10, так что всего выбирается не более 100 000 значений.
Вы также можете использовать другие методы, чтобы не получать все данные сразу. Виртуальная прокрутка в сочетании с регулированием каждого запроса может значительно повысить производительность. Вам также следует рассмотреть возможность использования сокращенного набора данных, если вам не нужны точные значения:
- getHyperCubeBinnedData связывает точки данных в группы и отлично подходит для тепловых карт и 2D-графиков плотности.
- getHyperCubeContinuousData уменьшает количество точек в непрерывном измерении и отлично подходит для временных данных.
- getHyperCubeReducedData выполняет некоторую магию вейвлетов и отлично подходит для мини-диаграмм.
Selecting data. Выбор данных
Выборка – это фундаментальная часть ассоциативного механизма Qlik. Все поля и связи между ними содержатся в ассоциативной модели. Когда вы применяете выбор, вы не только применяете фильтр в модели данных, но также демонстрируете связи между вашими источниками данных.
Applying selections. Применение выделений
Выборки можно применять с помощью методов, представленных в модели, возвращенной из useModel
хука.
Поскольку универсальный объект может содержать несколько гиперкубов, вам всегда нужно указать, какой гиперкуб вы хотите выбрать, указав его путь JSON в качестве первого аргумента:
import { useModel } from '@nebula.js/stardust'; // ... component() { const model = useModel(); useEffect(() => { model.selectHyperCubeCells('/qHyperCubeDef', [1], []); }, [model]) }
Шаблоны выбора. Selection patterns
Есть два разных шаблона выбора: мгновенный и модальный.
Мгновенный выбор. Instant selections
Как видно из названия, этот тип шаблона является немедленным и фильтрует как источник выбора, так и все, на что он влияет.
В следующем примере, как только значение выбрано на гистограмме, фильтрация применяется мгновенно, и обе диаграммы немедленно обновляются отфильтрованными данными:
Модальный выбор. Modal selections
Когда инициируется модальный выбор, источник выбора входит в форму модального состояния, которое позволяет пользователю изменять выбор до подтверждения изменений.
В следующем примере пользователь сначала выбирает одно значение на линейчатой диаграмме, после чего другие диаграммы обновляются, как и раньше. Однако гистограмма по-прежнему содержит все доступные данные и позволяет пользователю выбрать другое значение перед подтверждением изменений и обновлением самой гистограммы:
Чтобы реализовать этот тип паттерна, вам необходимо выполнить несколько простых шагов useSelections
в сочетании с useModel
ними:
- Войдите в модальное состояние, позвонив
beginSelections
. - Выберите значения.
- Обеспечьте визуальную обратную связь с пользователем о том, что было выбрано, например, изменив прозрачность выбранных значений.
- Следите за выходом из модального состояния, чтобы сбросить визуальную обратную связь.
import { useModel, useSelections, useElement } from '@nebula.js/stardust'; // ... component() { const element = useElement(); const model = useModel(); const selections = useSelections(); useEffect(() => { const clicked = () => { 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 () => { element.removeEventListener('click', clicked); } }, [element, model, selections]); useEffect(() => { if (layout.qSelectionInfo.qInSelections) { // 3. update with visual feedback on active selections // YOUR CODE HERE } else { // 4. normal update // YOUR CODE HERE } }, [layout]); }