@amcharts/amcharts5
Version:
amCharts 5
373 lines • 11.4 kB
JavaScript
import { EventDispatcher } from "./EventDispatcher";
import { Disposer, MultiDisposer } from "./Disposer";
import * as $array from "./Array";
import * as $object from "./Object";
import * as $type from "./Type";
function disposeSettings(settings) {
$object.each(settings, (_key, value) => {
if ($type.isObject(value) && typeof value.dispose === "function") {
value.enableDispose = true;
value.dispose();
}
});
}
export class TemplateState {
constructor(name, template, settings) {
this._name = name;
this._template = template;
this._settings = settings;
}
_dispose() {
disposeSettings(this._settings);
}
get(key, fallback) {
const value = this._settings[key];
if (value !== undefined) {
return value;
}
else {
return fallback;
}
}
set(key, value) {
this._settings[key] = value;
// TODO maybe only do this if the value changed ?
this._template._stateChanged(this._name);
}
remove(key) {
delete this._settings[key];
// TODO maybe only do this if the value changed ?
this._template._stateChanged(this._name);
}
setAll(settings) {
$object.keys(settings).forEach((key) => {
this._settings[key] = settings[key];
});
this._template._stateChanged(this._name);
}
_apply(other, seen) {
$object.each(this._settings, (key, value) => {
if (!seen[key] && !other._userSettings[key]) {
seen[key] = true;
other.setRaw(key, value);
// came from a theme, so it is not part of the configuration
other._computedSettings[key] = true;
}
});
}
}
export class TemplateStates {
constructor(template) {
this._states = {};
this._template = template;
}
_dispose() {
$object.each(this._states, (_key, state) => {
state._dispose();
});
}
lookup(name) {
return this._states[name];
}
create(name, settings) {
const state = this._states[name];
if (state) {
state.setAll(settings);
return state;
}
else {
const state = new TemplateState(name, this._template, settings);
this._states[name] = state;
this._template._stateChanged(name);
return state;
}
}
remove(name) {
delete this._states[name];
this._template._stateChanged(name);
}
_apply(entity, state) {
$object.each(this._states, (key, value) => {
let seen = state.states[key];
if (seen == null) {
seen = state.states[key] = {};
}
const other = entity.states.create(key, {});
value._apply(other, seen);
});
}
}
export class TemplateAdapters {
constructor() {
this._callbacks = {};
}
add(key, callback) {
let callbacks = this._callbacks[key];
if (callbacks === undefined) {
callbacks = this._callbacks[key] = [];
}
callbacks.push(callback);
return new Disposer(() => {
$array.removeFirst(callbacks, callback);
if (callbacks.length === 0) {
delete this._callbacks[key];
}
});
}
remove(key) {
const callbacks = this._callbacks[key];
if (callbacks !== undefined) {
delete this._callbacks[key];
}
}
_apply(entity) {
const disposers = [];
$object.each(this._callbacks, (key, callbacks) => {
$array.each(callbacks, (callback) => {
disposers.push(entity.adapters.add(key, callback));
});
});
return new MultiDisposer(disposers);
}
}
// TODO maybe extend from Properties ?
export class Template {
constructor(settings, isReal) {
this._disposed = false;
this._privateSettings = {};
this._computedSettings = {};
// TODO code duplication with Properties
this._settingEvents = {};
this._privateSettingEvents = {};
this._entities = [];
this.states = new TemplateStates(this);
this.adapters = new TemplateAdapters();
this.events = new EventDispatcher();
if (!isReal) {
throw new Error("You cannot use `new Class()`, instead use `Class.new()`");
}
this._settings = settings;
}
/**
* Use this method to create an instance of this class.
*
* @see {@link https://www.amcharts.com/docs/v5/getting-started/#New_element_syntax} for more info
* @param root Root element
* @param settings Settings
* @param template Template
* @return Instantiated object
*/
static new(settings) {
return new Template(settings, true);
}
_dispose() {
disposeSettings(this._settings);
disposeSettings(this._privateSettings);
}
/**
* Returns `true` if this element is disposed.
*
* @return Disposed
*/
isDisposed() {
return this._disposed;
}
/**
* Disposes this object.
*/
dispose() {
if (!this._disposed) {
this._disposed = true;
this._dispose();
}
}
_checkDisposed() {
if (this._disposed) {
throw new Error("Template is disposed");
}
}
/**
* Array of all entities using this template.
*/
get entities() {
return this._entities;
}
get(key, fallback) {
this._checkDisposed();
const value = this._settings[key];
if (value !== undefined) {
return value;
}
else {
return fallback;
}
}
setRaw(key, value) {
this._checkDisposed();
delete this._computedSettings[key];
this._settings[key] = value;
}
set(key, value) {
this._checkDisposed();
delete this._computedSettings[key];
if (this._settings[key] !== value) {
this.setRaw(key, value);
this._entities.forEach((entity) => {
entity._setTemplateProperty(this, key, value);
});
}
}
/**
* Same as `set()`, but for a value the library works out itself rather than
* one that was asked for, so that it can be left out when serializing.
*
* @ignore
*/
_setC(key, value) {
const authored = !this._computedSettings[key] && this._settings[key] === value;
this.set(key, value);
if (!authored) {
this._computedSettings[key] = true;
}
}
/**
* Sets multiple computed settings at once.
*
* @ignore
*/
_setCAll(settings) {
$object.each(settings, (key, value) => {
this._setC(key, value);
});
}
/**
* Flags already-set settings as computed, without writing anything.
*
* @ignore
*/
_markC(...keys) {
$array.each(keys, (key) => {
this._computedSettings[key] = true;
});
return this;
}
remove(key) {
this._checkDisposed();
if (key in this._settings) {
delete this._settings[key];
delete this._computedSettings[key];
this._entities.forEach((entity) => {
entity._removeTemplateProperty(key);
});
}
}
removeAll() {
this._checkDisposed();
$object.each(this._settings, (key, _value) => {
this.remove(key);
});
}
getPrivate(key, fallback) {
this._checkDisposed();
const value = this._privateSettings[key];
if (value !== undefined) {
return value;
}
else {
return fallback;
}
}
setPrivateRaw(key, value) {
this._checkDisposed();
this._privateSettings[key] = value;
return value;
}
setPrivate(key, value) {
this._checkDisposed();
if (this._privateSettings[key] !== value) {
this.setPrivateRaw(key, value);
this._entities.forEach((entity) => {
entity._setTemplatePrivateProperty(this, key, value);
});
}
return value;
}
removePrivate(key) {
this._checkDisposed();
if (key in this._privateSettings) {
delete this._privateSettings[key];
this._entities.forEach((entity) => {
entity._removeTemplatePrivateProperty(key);
});
}
}
setAll(value) {
this._checkDisposed();
$object.each(value, (key, value) => {
this.set(key, value);
});
}
// TODO code duplication with Properties
on(key, callback) {
this._checkDisposed();
let events = this._settingEvents[key];
if (events === undefined) {
events = this._settingEvents[key] = [];
}
events.push(callback);
return new Disposer(() => {
$array.removeFirst(events, callback);
if (events.length === 0) {
delete this._settingEvents[key];
}
});
}
// TODO code duplication with Properties
onPrivate(key, callback) {
this._checkDisposed();
let events = this._privateSettingEvents[key];
if (events === undefined) {
events = this._privateSettingEvents[key] = [];
}
events.push(callback);
return new Disposer(() => {
$array.removeFirst(events, callback);
if (events.length === 0) {
delete this._privateSettingEvents[key];
}
});
}
_apply(entity, state) {
this._checkDisposed();
const disposers = [];
$object.each(this._settingEvents, (key, events) => {
$array.each(events, (event) => {
disposers.push(entity.on(key, event));
});
});
$object.each(this._privateSettingEvents, (key, events) => {
$array.each(events, (event) => {
disposers.push(entity.onPrivate(key, event));
});
});
this.states._apply(entity, state);
disposers.push(this.adapters._apply(entity));
disposers.push(entity.events.copyFrom(this.events));
return new MultiDisposer(disposers);
}
_setObjectTemplate(entity) {
this._checkDisposed();
this._entities.push(entity);
}
_removeObjectTemplate(entity) {
//this._checkDisposed();
$array.remove(this._entities, entity);
}
_stateChanged(name) {
this._checkDisposed();
this._entities.forEach((entity) => {
entity._applyStateByKey(name);
});
}
}
//# sourceMappingURL=Template.js.map