added simple math and charts modules
This commit is contained in:
@@ -18,7 +18,9 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"farmos/farmos": "^3.0",
|
"farmos/farmos": "^3.0",
|
||||||
"oomphinc/composer-installers-extender": "^2.0",
|
"oomphinc/composer-installers-extender": "^2.0",
|
||||||
"wikimedia/composer-merge-plugin": "^2.0"
|
"wikimedia/composer-merge-plugin": "^2.0",
|
||||||
|
"drupal/views_simple_math_field": "^3.0",
|
||||||
|
"drupal/charts": "^5.1"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
|
|||||||
150
composer.lock
generated
150
composer.lock
generated
@@ -4,8 +4,54 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "103f9b8db31610ca1687c620aeec857d",
|
"content-hash": "b863e8929cb118de1242b4471666ad20",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "andileco/eval-math",
|
||||||
|
"version": "3.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/andileco/eval-math.git",
|
||||||
|
"reference": "52ff5728ad51961a630cc957328764cb02ab5c51"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/andileco/eval-math/zipball/52ff5728ad51961a630cc957328764cb02ab5c51",
|
||||||
|
"reference": "52ff5728ad51961a630cc957328764cb02ab5c51",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php-coveralls/php-coveralls": "^2",
|
||||||
|
"phpunit/phpunit": "^5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Andileco\\Util\\EvalMath\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"description": "EvalMath",
|
||||||
|
"keywords": [
|
||||||
|
"EvalMath"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/andileco/eval-math/issues",
|
||||||
|
"source": "https://github.com/andileco/eval-math/tree/3.0.1"
|
||||||
|
},
|
||||||
|
"time": "2022-07-21T21:04:26+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "asm89/stack-cors",
|
"name": "asm89/stack-cors",
|
||||||
"version": "v2.2.0",
|
"version": "v2.2.0",
|
||||||
@@ -1339,6 +1385,58 @@
|
|||||||
"issues": "https://www.drupal.org/project/issues/admin_toolbar"
|
"issues": "https://www.drupal.org/project/issues/admin_toolbar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/charts",
|
||||||
|
"version": "5.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/charts.git",
|
||||||
|
"reference": "5.1.1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/charts-5.1.1.zip",
|
||||||
|
"reference": "5.1.1",
|
||||||
|
"shasum": "81529ec926462ddc62e9f9f78d47b036af566b6b"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"drupal/core": "^10.3 || ^11"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"datestamp": "1733170631",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "andileco",
|
||||||
|
"homepage": "https://www.drupal.org/user/2054544"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nikathone",
|
||||||
|
"homepage": "https://www.drupal.org/user/2421800"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quicksketch",
|
||||||
|
"homepage": "https://www.drupal.org/user/35821"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A charting API for Drupal that provides chart elements and integration with Views.",
|
||||||
|
"homepage": "https://www.drupal.org/project/charts",
|
||||||
|
"support": {
|
||||||
|
"source": "https://git.drupalcode.org/project/charts"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drupal/config_update",
|
"name": "drupal/config_update",
|
||||||
"version": "2.0.0-alpha4",
|
"version": "2.0.0-alpha4",
|
||||||
@@ -3415,6 +3513,56 @@
|
|||||||
"irc": "irc://irc.freenode.org/drupal-contribute"
|
"irc": "irc://irc.freenode.org/drupal-contribute"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/views_simple_math_field",
|
||||||
|
"version": "3.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/views_simple_math_field.git",
|
||||||
|
"reference": "3.0.2"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/views_simple_math_field-3.0.2.zip",
|
||||||
|
"reference": "3.0.2",
|
||||||
|
"shasum": "6620ee614bbaf68b9c26227e01c74299be47a6d8"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"andileco/eval-math": "^3.0.1",
|
||||||
|
"drupal/core": "^8.7|^9.0 || ^10 || ^11"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"datestamp": "1719379402",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0+"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "andileco",
|
||||||
|
"homepage": "https://www.drupal.org/user/2054544"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Beakerboy",
|
||||||
|
"homepage": "https://www.drupal.org/user/1700098"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Math operations over selected fields",
|
||||||
|
"homepage": "https://www.drupal.org/project/views_simple_math_field",
|
||||||
|
"support": {
|
||||||
|
"source": "http://cgit.drupalcode.org/views_simple_math_field",
|
||||||
|
"issues": "https://www.drupal.org/project/issues/views_simple_math_field"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drush/drush",
|
"name": "drush/drush",
|
||||||
"version": "12.5.3",
|
"version": "12.5.3",
|
||||||
|
|||||||
7
vendor/andileco/eval-math/.gitignore
vendored
Normal file
7
vendor/andileco/eval-math/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/.idea
|
||||||
|
/vendor
|
||||||
|
/composer.lock
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.buildpath
|
||||||
|
/build
|
||||||
21
vendor/andileco/eval-math/.travis.yml
vendored
Normal file
21
vendor/andileco/eval-math/.travis.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
language: php
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- composer self-update
|
||||||
|
- composer config platform.php $PHP_VERSION
|
||||||
|
- composer install --prefer-source --no-interaction --dev
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
include:
|
||||||
|
- php: '5.6'
|
||||||
|
env: PHP_VERSION=5.6
|
||||||
|
- php: '7.0'
|
||||||
|
env: PHP_VERSION=7.0
|
||||||
|
- php: '7.1'
|
||||||
|
env: PHP_VERSION=7.1
|
||||||
|
- php: '7.2'
|
||||||
|
env: PHP_VERSION=7.2
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- php vendor/bin/php-coveralls -v
|
||||||
25
vendor/andileco/eval-math/LICENSE
vendored
Normal file
25
vendor/andileco/eval-math/LICENSE
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
LICENSE
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1 Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
78
vendor/andileco/eval-math/README.md
vendored
Normal file
78
vendor/andileco/eval-math/README.md
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
Composer/Packagist version of EvalMath by Miles Kaufman
|
||||||
|
Copyright (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
EvalMath - safely evaluate math expressions
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
Use the EvalMath class when you want to evaluate mathematical expressions
|
||||||
|
from untrusted sources. You can define your own variables and functions,
|
||||||
|
which are stored in the object. Try it, it's fun!
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
--------
|
||||||
|
`$m = new EvalMath;`
|
||||||
|
|
||||||
|
`// basic evaluation:`
|
||||||
|
`$result = $m->evaluate('2+2');`
|
||||||
|
|
||||||
|
`// supports: order of operation; parentheses; negation; built-in functions`
|
||||||
|
`$result = $m->evaluate('-8(5/2)^2*(1-sqrt(4))-8');`
|
||||||
|
|
||||||
|
`// create your own variables`
|
||||||
|
`$m->evaluate('a = e^(ln(pi))');`
|
||||||
|
|
||||||
|
`// or functions`
|
||||||
|
`$m->evaluate('f(x,y) = x^2 + y^2 - 2x*y + 1');`
|
||||||
|
|
||||||
|
`// and then use them`
|
||||||
|
`$result = $m->evaluate('3*f(42,a)');`
|
||||||
|
|
||||||
|
`// use methods (calc functions)
|
||||||
|
`$m->evaluate('1+max(2,3)') // => 4`
|
||||||
|
`$m->evaluate('if(1=2, 2+2, 5+5') // => 10
|
||||||
|
|
||||||
|
METHODS
|
||||||
|
-------
|
||||||
|
`$m->evaluate($expr)`
|
||||||
|
Evaluates the expression and returns the result. If an error occurs,
|
||||||
|
prints a warning and returns false. If $expr is a function assignment,
|
||||||
|
returns true on success.
|
||||||
|
|
||||||
|
`$m->e($expr)`
|
||||||
|
A synonym for $m->evaluate().
|
||||||
|
|
||||||
|
`$m->vars()`
|
||||||
|
Returns an associative array of all user-defined variables and values.
|
||||||
|
|
||||||
|
`$m->funcs()`
|
||||||
|
Returns an array of all user-defined functions.
|
||||||
|
|
||||||
|
CALC METHODS (CALC FUNCTIONS)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
- `max(n...,m)` returns one of given arguments with maximal value
|
||||||
|
- `min(n...,m)` returns one of given arguments with minimal value
|
||||||
|
- `if(expr, true_value, false_value)` (has a `iif` synonym) returns `true_value` of `false_value` depends of `expr` evaluation result
|
||||||
|
- `round(n,m)` returns rounded n value with m precision
|
||||||
|
|
||||||
|
CREATE YOUR OWN CUSTOM CALC METHODS (CALC FUNCTIONS)
|
||||||
|
-----------------------------------------------
|
||||||
|
You can create custom classes, that implements custom calc methods.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
- Improve documentation
|
||||||
|
- Ability to add custom operators
|
||||||
|
- More tests
|
||||||
|
|
||||||
|
CREDITS AND COPYRIGHTS
|
||||||
|
----------------------
|
||||||
|
This software integrates several libraries and patches by:
|
||||||
|
|
||||||
|
- Original EvalMath library, (C) 2005 Miles Kaufmann <http://www.twmagic.com/>
|
||||||
|
- Modifications for 'calc functions' by Moodle, <https://github.com/moodle/moodle>
|
||||||
|
- Composer/Packagist version, (C) Daniel Bojdo, <https://github.com/dbojdo>
|
||||||
|
|
||||||
26
vendor/andileco/eval-math/composer.json
vendored
Normal file
26
vendor/andileco/eval-math/composer.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name" : "andileco/eval-math",
|
||||||
|
"description" : "EvalMath",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"type" : "library",
|
||||||
|
"keywords" : [
|
||||||
|
"EvalMath"
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^7 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^5",
|
||||||
|
"php-coveralls/php-coveralls": "^2"
|
||||||
|
},
|
||||||
|
"autoload" : {
|
||||||
|
"psr-4" : {
|
||||||
|
"Andileco\\Util\\EvalMath\\" : "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.x-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
vendor/andileco/eval-math/phpunit.xml.dist
vendored
Normal file
16
vendor/andileco/eval-math/phpunit.xml.dist
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit bootstrap="./vendor/autoload.php">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="EvalMath Test Suite">
|
||||||
|
<directory>./tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">src/</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
<logging>
|
||||||
|
<log type="coverage-clover" target="build/logs/clover.xml" />
|
||||||
|
</logging>
|
||||||
|
</phpunit>
|
||||||
511
vendor/andileco/eval-math/src/EvalMath.php
vendored
Normal file
511
vendor/andileco/eval-math/src/EvalMath.php
vendored
Normal file
@@ -0,0 +1,511 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath;
|
||||||
|
|
||||||
|
use Andileco\Util\EvalMath\Exception\AbstractEvalMathException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\BuiltInFunctionRedefinitionException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\ConstantAssignmentException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\DivisionByZeroException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\ExpectingTokenException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\IllegalCharacterException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\InternalErrorException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\InvalidArgumentCountException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\OperatorLacksOperandException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\OperatorRequiredException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UndefinedVariableException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UndefinedVariableInFunctionDefinitionException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UnexpectedOperatorException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UnexpectedTokenException;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Conditional;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Maximum;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Minimum;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Round;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EvalMath
|
||||||
|
*/
|
||||||
|
class EvalMath
|
||||||
|
{
|
||||||
|
const NAME_PATTERN = '[a-z][a-z0-9_]*';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $suppress_errors = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $last_error = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $v = ['e'=>2.71,'pi'=>3.14]; // variables (and constants)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $f = []; // user-defined functions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $vb = ['e', 'pi']; // constants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $fb = [ // built-in functions
|
||||||
|
'sin','sinh','arcsin','asin','arcsinh','asinh',
|
||||||
|
'cos','cosh','arccos','acos','arccosh','acosh',
|
||||||
|
'tan','tanh','arctan','atan','arctanh','atanh',
|
||||||
|
'sqrt','abs','ln','log'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Calc functions
|
||||||
|
// public $fc =['average'=>[-1], 'max'=>[-1], 'min'=>[-1], 'iif'=>[3]];
|
||||||
|
/** @var MethodsRegistry */
|
||||||
|
protected $fc;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// make the variables a little more accurate
|
||||||
|
$this->v['pi'] = pi();
|
||||||
|
$this->v['e'] = exp(1);
|
||||||
|
$this->fc = (new MethodsRegistry)
|
||||||
|
->set(new Conditional)
|
||||||
|
->set((new Conditional)->setName('iif'))
|
||||||
|
->set(new Maximum)
|
||||||
|
->set(new Minimum)
|
||||||
|
->set(new Round);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return MethodsRegistry
|
||||||
|
*/
|
||||||
|
public function getMethodsRegistry()
|
||||||
|
{
|
||||||
|
return $this->fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $expr
|
||||||
|
* @return mixed
|
||||||
|
* @throws BuiltInFunctionRedefinitionException
|
||||||
|
* @throws ConstantAssignmentException
|
||||||
|
* @throws DivisionByZeroException
|
||||||
|
* @throws ExpectingTokenException
|
||||||
|
* @throws IllegalCharacterException
|
||||||
|
* @throws InternalErrorException
|
||||||
|
* @throws InvalidArgumentCountException
|
||||||
|
* @throws OperatorLacksOperandException
|
||||||
|
* @throws OperatorRequiredException
|
||||||
|
* @throws UndefinedVariableException
|
||||||
|
* @throws UndefinedVariableInFunctionDefinitionException
|
||||||
|
* @throws UnexpectedOperatorException
|
||||||
|
* @throws UnexpectedTokenException
|
||||||
|
*/
|
||||||
|
public function e($expr)
|
||||||
|
{
|
||||||
|
return $this->evaluate($expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $expr
|
||||||
|
* @return mixed
|
||||||
|
* @throws BuiltInFunctionRedefinitionException
|
||||||
|
* @throws ConstantAssignmentException
|
||||||
|
* @throws DivisionByZeroException
|
||||||
|
* @throws ExpectingTokenException
|
||||||
|
* @throws IllegalCharacterException
|
||||||
|
* @throws InternalErrorException
|
||||||
|
* @throws InvalidArgumentCountException
|
||||||
|
* @throws OperatorLacksOperandException
|
||||||
|
* @throws OperatorRequiredException
|
||||||
|
* @throws UndefinedVariableException
|
||||||
|
* @throws UndefinedVariableInFunctionDefinitionException
|
||||||
|
* @throws UnexpectedOperatorException
|
||||||
|
* @throws UnexpectedTokenException
|
||||||
|
*/
|
||||||
|
public function evaluate($expr)
|
||||||
|
{
|
||||||
|
$this->last_error = null;
|
||||||
|
$expr = rtrim(trim($expr), ';'); // strip semicolons at the end
|
||||||
|
|
||||||
|
//===============
|
||||||
|
// is it a variable assignment?
|
||||||
|
if (preg_match('/^\s*([a-z]\w*)\s*=\s*(.+)$/', $expr, $matches)) {
|
||||||
|
if (in_array($matches[1], $this->vb)) { // make sure we're not assigning to a constant
|
||||||
|
throw new ConstantAssignmentException([':constant' => $matches[1]]);
|
||||||
|
}
|
||||||
|
if (($tmp = $this->pfx($this->nfx($matches[2]))) === false) return false; // get the result and make sure it's good
|
||||||
|
$this->v[$matches[1]] = $tmp; // if so, stick it in the variable array
|
||||||
|
return $this->v[$matches[1]]; // and return the resulting value
|
||||||
|
//===============
|
||||||
|
// is it a function assignment?
|
||||||
|
} elseif (preg_match('/^\s*([a-z]\w*)\s*\(\s*([a-z]\w*(?:\s*,\s*[a-z]\w*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
|
||||||
|
$fnn = $matches[1]; // get the function name
|
||||||
|
if (in_array($matches[1], $this->fb)) { // make sure it isn't built in
|
||||||
|
throw new BuiltInFunctionRedefinitionException([':function' =>$matches[1]]);
|
||||||
|
}
|
||||||
|
$args = explode(",", preg_replace("/\s+/", "", $matches[2])); // get the arguments
|
||||||
|
if (($stack = $this->nfx($matches[3])) === false) return false; // see if it can be converted to postfix
|
||||||
|
for ($i = 0; $i<count($stack); $i++) { // freeze the state of the non-argument variables
|
||||||
|
$token = $stack[$i];
|
||||||
|
if (preg_match('/^[a-z]\w*$/', $token) and !in_array($token, $args)) {
|
||||||
|
if (array_key_exists($token, $this->v)) {
|
||||||
|
$stack[$i] = $this->v[$token];
|
||||||
|
} else {
|
||||||
|
throw new UndefinedVariableInFunctionDefinitionException([':token'=>$token]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->f[$fnn] = ['args'=>$args, 'func'=>$stack];
|
||||||
|
return true;
|
||||||
|
//===============
|
||||||
|
} else {
|
||||||
|
return $this->pfx($this->nfx($expr)); // straight up evaluation, woo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function vars()
|
||||||
|
{
|
||||||
|
$output = $this->v;
|
||||||
|
unset($output['pi'], $output['e']);
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function funcs()
|
||||||
|
{
|
||||||
|
$output = [];
|
||||||
|
foreach ($this->f as $fnn=>$dat)
|
||||||
|
$output[] = $fnn . '(' . implode(',', $dat['args']) . ')';
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===================== HERE BE INTERNAL METHODS ====================\\
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert infix to postfix notation
|
||||||
|
*
|
||||||
|
* @param $expr
|
||||||
|
* @return array|bool
|
||||||
|
* @throws ExpectingTokenException
|
||||||
|
* @throws IllegalCharacterException
|
||||||
|
* @throws InternalErrorException
|
||||||
|
* @throws InvalidArgumentCountException
|
||||||
|
* @throws OperatorLacksOperandException
|
||||||
|
* @throws OperatorRequiredException
|
||||||
|
* @throws UnexpectedOperatorException
|
||||||
|
* @throws UnexpectedTokenException
|
||||||
|
*/
|
||||||
|
public function nfx($expr)
|
||||||
|
{
|
||||||
|
|
||||||
|
$index = 0;
|
||||||
|
$stack = new Stack();
|
||||||
|
$output = []; // postfix form of expression, to be passed to pfx()
|
||||||
|
// $expr = trim(strtolower($expr));
|
||||||
|
$expr = trim($expr);
|
||||||
|
|
||||||
|
$ops = ['+', '-', '*', '/', '^', '_', '%', '>', '<', '<=', '>=', '=='];
|
||||||
|
$ops_r = ['+' => 0, '-' => 0, '*' => 0, '/' => 0, '^' => 1, '%' => 0]; // right-associative operator?
|
||||||
|
$ops_p = ['+' => 0, '-' => 0, '*' => 1, '/' => 1, '_' => 1, '^' => 2, '%' => 1, '>' => 3, '<' => 3, '<=' => 3, '>=' => 3, '==' => 3]; // operator precedence
|
||||||
|
|
||||||
|
$expecting_op = false; // we use this in syntax-checking the expression
|
||||||
|
// and determining when a - is a negation
|
||||||
|
|
||||||
|
if (preg_match('/[^\%\w\s+*^\/()\.,-<>=]/', $expr, $matches)) { // make sure the characters are all good
|
||||||
|
throw new IllegalCharacterException([':character'=>$matches[0]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1) { // 1 Infinite Loop ;)
|
||||||
|
$op = substr($expr, $index, 2);
|
||||||
|
if (!in_array($op, $ops)) {
|
||||||
|
$op = substr($expr, $index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find out if we're currently at the beginning of a number/variable/function/parenthesis/operand
|
||||||
|
// $ex = preg_match('/^([A-Za-z]\w*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
|
||||||
|
$ex = preg_match('/^('.static::NAME_PATTERN.'\(?|\d+(?:\.\d*)?(?:(e[+-]?)\d*)?|\.\d+|\()/', substr($expr, $index), $match);
|
||||||
|
//===============
|
||||||
|
if ($op == '-' and !$expecting_op) { // is it a negation instead of a minus?
|
||||||
|
$stack->push('_'); // put a negation on the stack
|
||||||
|
$index++;
|
||||||
|
} elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
|
||||||
|
throw new IllegalCharacterException([':character'=>'_']);
|
||||||
|
//===============
|
||||||
|
} elseif ((in_array($op, $ops) or $ex) and $expecting_op) { // are we putting an operator on the stack?
|
||||||
|
if ($ex) { // are we expecting an operator but have a number/variable/function/opening parethesis?
|
||||||
|
throw new OperatorRequiredException();
|
||||||
|
/*
|
||||||
|
* Implicit multiplication currently is not supported
|
||||||
|
*
|
||||||
|
$op = '*';
|
||||||
|
$index--; // it's an implicit multiplication
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
// heart of the algorithm:
|
||||||
|
while($stack->count > 0 and ($o2 = $stack->last()) and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] : $ops_p[$op] <= $ops_p[$o2])) {
|
||||||
|
$output[] = $stack->pop(); // pop stuff off the stack into the output
|
||||||
|
}
|
||||||
|
// many thanks: http://en.wikipedia.org/wiki/Reverse_Polish_notation#The_algorithm_in_detail
|
||||||
|
$stack->push($op); // finally put OUR operator onto the stack
|
||||||
|
$index += strlen($op);
|
||||||
|
$expecting_op = false;
|
||||||
|
//===============
|
||||||
|
} elseif ($op == ')' and $expecting_op) { // ready to close a parenthesis?
|
||||||
|
while (($o2 = $stack->pop()) != '(') { // pop off the stack back to the last (
|
||||||
|
if (null === $o2) {
|
||||||
|
throw new UnexpectedTokenException(['token'=>')']);
|
||||||
|
} else {
|
||||||
|
$output[] = $o2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (preg_match("/^([A-Za-z]\w*)\($/", $stack->last(2) ?? '', $matches)) { // did we just close a function?
|
||||||
|
$fnn = $matches[1]; // get the function name
|
||||||
|
$arg_count = $stack->pop(); // see how many arguments there were (cleverly stored on the stack, thank you)
|
||||||
|
$fn = $stack->pop();
|
||||||
|
$output[] = ['fn' => $fn, 'fnn' => $fnn, 'argcount' => $arg_count]; // send function to output
|
||||||
|
if (in_array($fnn, $this->fb)) { // check the argument count
|
||||||
|
if ($arg_count > 1) {
|
||||||
|
throw new InvalidArgumentCountException();
|
||||||
|
}
|
||||||
|
} elseif (isset($this->fc[$fnn])) {
|
||||||
|
$counts = $this->fc[$fnn];
|
||||||
|
if (in_array(-1, $counts) and $arg_count > 0) {
|
||||||
|
} elseif (!in_array($arg_count, $counts)) {
|
||||||
|
throw new InvalidArgumentCountException();
|
||||||
|
}
|
||||||
|
} elseif (array_key_exists($fnn, $this->f)) {
|
||||||
|
if ($arg_count != count($this->f[$fnn]['args'])) {
|
||||||
|
throw new InvalidArgumentCountException();
|
||||||
|
}
|
||||||
|
} else { // did we somehow push a non-function on the stack? this should never happen
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$index++;
|
||||||
|
//===============
|
||||||
|
} elseif ($op == ',' and $expecting_op) { // did we just finish a function argument?
|
||||||
|
while (($o2 = $stack->pop()) != '(') {
|
||||||
|
if (null === $o2) {
|
||||||
|
throw new UnexpectedTokenException([':token'=>',']);
|
||||||
|
} // oops, never had a (
|
||||||
|
else {
|
||||||
|
$output[] = $o2;
|
||||||
|
} // pop the argument expression stuff and push onto the output
|
||||||
|
}
|
||||||
|
// make sure there was a function
|
||||||
|
// if (!preg_match("/^([A-Za-z]\w*)\($/", $stack->last(2), $matches)) {
|
||||||
|
if (!preg_match('/^('.self::NAME_PATTERN.')\($/', $stack->last(2) ?? '', $matches)) {
|
||||||
|
throw new UnexpectedTokenException([':token'=>',']);
|
||||||
|
}
|
||||||
|
$stack->push($stack->pop()+1); // increment the argument count
|
||||||
|
$stack->push('('); // put the ( back on, we'll need to pop back to it again
|
||||||
|
$index++;
|
||||||
|
$expecting_op = false;
|
||||||
|
//===============
|
||||||
|
} elseif ($op == '(' and !$expecting_op) {
|
||||||
|
$stack->push('('); // that was easy
|
||||||
|
$index++;
|
||||||
|
$allow_neg = true;
|
||||||
|
//===============
|
||||||
|
} elseif ($ex and !$expecting_op) { // do we now have a function/variable/number?
|
||||||
|
$expecting_op = true;
|
||||||
|
$val = $match[1];
|
||||||
|
// if (preg_match("/^([A-Za-z]\w*)\($/", $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
|
||||||
|
if (preg_match('/^('.static::NAME_PATTERN.')\($/', $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
|
||||||
|
if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f) or isset($this->fc[$matches[1]])) { // it's a func
|
||||||
|
$stack->push($val);
|
||||||
|
$stack->push(1);
|
||||||
|
$stack->push('(');
|
||||||
|
$expecting_op = false;
|
||||||
|
} else { // it's a var w/ implicit multiplication
|
||||||
|
$val = $matches[1];
|
||||||
|
$output[] = $val;
|
||||||
|
}
|
||||||
|
} else { // it's a plain old var or num
|
||||||
|
$output[] = $val;
|
||||||
|
}
|
||||||
|
$index += strlen($val);
|
||||||
|
//===============
|
||||||
|
} elseif ($op == ')') { // miscellaneous error checking
|
||||||
|
if ($stack->last() != '(' or $stack->last(2) != 1) {
|
||||||
|
throw new UnexpectedTokenException([':token' => ')']);
|
||||||
|
}
|
||||||
|
// did we just close a function?
|
||||||
|
if (preg_match('/^(' . static::NAME_PATTERN . ')\($/', $stack->last(3) ?? '', $matches)) {
|
||||||
|
$stack->pop();// (
|
||||||
|
$stack->pop();// 1
|
||||||
|
$fn = $stack->pop();
|
||||||
|
$fnn = $matches[1]; // get the function name
|
||||||
|
$counts = $this->fc[$fnn];
|
||||||
|
if (!in_array(0, $counts)) {
|
||||||
|
throw new InvalidArgumentCountException([':given' => 0, ':accept' => $counts]);
|
||||||
|
}
|
||||||
|
$output[] = ['fn' => $fn, 'fnn' => $fnn, 'argcount' => 0]; // send function to output
|
||||||
|
$index++;
|
||||||
|
$expecting_op = true;
|
||||||
|
}
|
||||||
|
throw new UnexpectedTokenException([':token' => ')']);
|
||||||
|
} elseif (in_array($op, $ops) and !$expecting_op) {
|
||||||
|
throw new UnexpectedOperatorException([':operator'=>$op]);
|
||||||
|
} else { // I don't even want to know what you did to get here
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
if ($index == strlen($expr)) {
|
||||||
|
if (in_array($op, $ops)) { // did we end with an operator? bad.
|
||||||
|
throw new OperatorLacksOperandException([':operator' => $op]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (substr($expr, $index, 1) == ' ') { // step the index past whitespace (pretty much turns whitespace
|
||||||
|
$index++; // into implicit multiplication if no operator is there)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
|
||||||
|
if ($op == '(') { // if there are (s on the stack, ()s were unbalanced
|
||||||
|
throw new ExpectingTokenException([':token' => ')']);
|
||||||
|
}
|
||||||
|
$output[] = $op;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* evaluate postfix notation
|
||||||
|
*
|
||||||
|
* @param $tokens
|
||||||
|
* @param array $vars
|
||||||
|
* @return bool|mixed|null
|
||||||
|
* @throws DivisionByZeroException
|
||||||
|
* @throws InternalErrorException
|
||||||
|
* @throws UndefinedVariableException
|
||||||
|
*/
|
||||||
|
public function pfx($tokens, $vars = [])
|
||||||
|
{
|
||||||
|
if ($tokens == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stack = new Stack();
|
||||||
|
|
||||||
|
foreach ($tokens as $token) { // nice and easy
|
||||||
|
if(is_array($token)) { // it's a function
|
||||||
|
$fnn = $token['fnn'];
|
||||||
|
$argcount = $token['argcount'];
|
||||||
|
if (in_array($fnn, $this->fb)) { // built-in function
|
||||||
|
if (is_null($op1 = $stack->pop())) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
$fnn = preg_replace("/^arc/", "a", $fnn); // for the 'arc' trig synonyms
|
||||||
|
if ($fnn == 'ln') {
|
||||||
|
$fnn = 'log';
|
||||||
|
}
|
||||||
|
eval('$stack->push(' . $fnn . '($op1));'); // perfectly safe eval()
|
||||||
|
} elseif (($m = $this->fc->findByName($fnn))) {
|
||||||
|
$args = [];
|
||||||
|
for ($i = $argcount-1; $i >= 0; $i--) {
|
||||||
|
if (null === ($args[] = $stack->pop())) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$res = $m->evaluate(...array_reverse($args));
|
||||||
|
if ($res === FALSE) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
$stack->push($res);
|
||||||
|
}elseif (array_key_exists($fnn, $this->f)) { // user function
|
||||||
|
// get args
|
||||||
|
$args = [];
|
||||||
|
for ($i = count($this->f[$fnn]['args'])-1; $i >= 0; $i--) {
|
||||||
|
if ( null === ($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$stack->push($this->pfx($this->f[$fnn]['func'], $args)); // yay... recursion!!!!
|
||||||
|
}
|
||||||
|
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
|
||||||
|
} elseif (in_array($token, ['+', '-', '*', '/', '^', '>', '<', '==', '<=', '>=', '%'], true)) {
|
||||||
|
if (is_null($op2 = $stack->pop())) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
if (is_null($op1 = $stack->pop())) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
switch ($token) {
|
||||||
|
case '+':
|
||||||
|
$stack->push($op1 + $op2);
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
$stack->push($op1 - $op2);
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
$stack->push($op1 * $op2);
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
if ($op2 == 0) {
|
||||||
|
throw new DivisionByZeroException();
|
||||||
|
}
|
||||||
|
$stack->push($op1 / $op2);
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
$stack->push(pow($op1, $op2));
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
$stack->push((int)($op1 > $op2));
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
$stack->push((int)($op1 < $op2));
|
||||||
|
break;
|
||||||
|
case '==':
|
||||||
|
$stack->push((int)($op1 == $op2));
|
||||||
|
break;
|
||||||
|
case '<=':
|
||||||
|
$stack->push((int)($op1 <= $op2));
|
||||||
|
break;
|
||||||
|
case '>=':
|
||||||
|
$stack->push((int)($op1 >= $op2));
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
$stack->push($op1 % $op2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
|
||||||
|
} elseif ($token == "_") {
|
||||||
|
$stack->push(-1*$stack->pop());
|
||||||
|
// if the token is a number or variable, push it on the stack
|
||||||
|
} else {
|
||||||
|
if (is_numeric($token)) {
|
||||||
|
$stack->push($token);
|
||||||
|
} elseif (array_key_exists($token, $this->v)) {
|
||||||
|
$stack->push($this->v[$token]);
|
||||||
|
} elseif (array_key_exists($token, $vars)) {
|
||||||
|
$stack->push($vars[$token]);
|
||||||
|
} else {
|
||||||
|
throw new UndefinedVariableException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // when we're out of tokens, the stack should have a single element, the final result
|
||||||
|
if ($stack->count != 1) {
|
||||||
|
throw new InternalErrorException();
|
||||||
|
}
|
||||||
|
return $stack->pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/andileco/eval-math/src/Exception/AbstractEvalMathException.php
vendored
Normal file
21
vendor/andileco/eval-math/src/Exception/AbstractEvalMathException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class AbstractEvalMathException extends Exception implements EvalMathException
|
||||||
|
{
|
||||||
|
protected $error = '';
|
||||||
|
|
||||||
|
public function __construct(array $parameters=[])
|
||||||
|
{
|
||||||
|
$message = strtr($this->error, $parameters);
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/BuiltInFunctionRedefinitionException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/BuiltInFunctionRedefinitionException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class BuiltInFunctionRedefinitionException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Cannot redefine built-in function :function()';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/ConstantAssignmentException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/ConstantAssignmentException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class ConstantAssignmentException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Cannot assign to constant :constant';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/DivisionByZeroException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/DivisionByZeroException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class DivisionByZeroException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Division by zero';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/EvalMathException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/EvalMathException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
interface EvalMathException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/ExpectingTokenException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/ExpectingTokenException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class ExpectingTokenException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = "Expecting ':token'";
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/IllegalCharacterException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/IllegalCharacterException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class IllegalCharacterException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = "illegal character ':character'";
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/InternalErrorException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/InternalErrorException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class InternalErrorException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Internal error';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/InvalidArgumentCountException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/InvalidArgumentCountException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidArgumentCountException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Wrong number of arguments';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/OperatorLacksOperandException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/OperatorLacksOperandException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class OperatorLacksOperandException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = "operator ':operator' lacks operand";
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/OperatorRequiredException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/OperatorRequiredException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class OperatorRequiredException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Operator required';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/UndefinedVariableException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/UndefinedVariableException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class UndefinedVariableException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = "Undefined variable";
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/UndefinedVariableInFunctionDefinitionException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/UndefinedVariableInFunctionDefinitionException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class UndefinedVariableInFunctionDefinitionException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Undefined variable :token in function definition';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/UnexpectedOperatorException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/UnexpectedOperatorException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class UnexpectedOperatorException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Unexpected operator \':operator\'';
|
||||||
|
}
|
||||||
14
vendor/andileco/eval-math/src/Exception/UnexpectedTokenException.php
vendored
Normal file
14
vendor/andileco/eval-math/src/Exception/UnexpectedTokenException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Exception;
|
||||||
|
|
||||||
|
|
||||||
|
class UnexpectedTokenException extends AbstractEvalMathException
|
||||||
|
{
|
||||||
|
protected $message = 'Unexpected \':token\'';
|
||||||
|
}
|
||||||
34
vendor/andileco/eval-math/src/Methods/AbstractMethod.php
vendored
Normal file
34
vendor/andileco/eval-math/src/Methods/AbstractMethod.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Methods;
|
||||||
|
|
||||||
|
|
||||||
|
abstract class AbstractMethod
|
||||||
|
{
|
||||||
|
protected $name = '';
|
||||||
|
|
||||||
|
protected $argument_count = [-1];
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName($name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
return clone $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArgumentCount()
|
||||||
|
{
|
||||||
|
return $this->argument_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function evaluate(...$args);
|
||||||
|
}
|
||||||
20
vendor/andileco/eval-math/src/Methods/Conditional.php
vendored
Normal file
20
vendor/andileco/eval-math/src/Methods/Conditional.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Methods;
|
||||||
|
|
||||||
|
|
||||||
|
class Conditional extends AbstractMethod
|
||||||
|
{
|
||||||
|
protected $name='if';
|
||||||
|
protected $argument_count = [3];
|
||||||
|
|
||||||
|
public function evaluate(...$args)
|
||||||
|
{
|
||||||
|
return $args[0] ? $args[1] : $args[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/andileco/eval-math/src/Methods/Maximum.php
vendored
Normal file
19
vendor/andileco/eval-math/src/Methods/Maximum.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Methods;
|
||||||
|
|
||||||
|
|
||||||
|
class Maximum extends AbstractMethod
|
||||||
|
{
|
||||||
|
protected $name='max';
|
||||||
|
|
||||||
|
public function evaluate(...$args)
|
||||||
|
{
|
||||||
|
return max($args);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
vendor/andileco/eval-math/src/Methods/Minimum.php
vendored
Normal file
19
vendor/andileco/eval-math/src/Methods/Minimum.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Methods;
|
||||||
|
|
||||||
|
|
||||||
|
class Minimum extends AbstractMethod
|
||||||
|
{
|
||||||
|
protected $name = 'min';
|
||||||
|
|
||||||
|
public function evaluate(...$args)
|
||||||
|
{
|
||||||
|
return min($args);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
vendor/andileco/eval-math/src/Methods/Round.php
vendored
Normal file
18
vendor/andileco/eval-math/src/Methods/Round.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Methods;
|
||||||
|
|
||||||
|
|
||||||
|
class Round extends AbstractMethod
|
||||||
|
{
|
||||||
|
protected $name = 'round';
|
||||||
|
|
||||||
|
public function evaluate(...$args)
|
||||||
|
{
|
||||||
|
if (!isset($args[1])) {
|
||||||
|
return round($args[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return round($args[0], $args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
vendor/andileco/eval-math/src/MethodsRegistry.php
vendored
Normal file
66
vendor/andileco/eval-math/src/MethodsRegistry.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath;
|
||||||
|
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use Countable;
|
||||||
|
use RuntimeException;
|
||||||
|
use Andileco\Util\EvalMath\Methods\AbstractMethod;
|
||||||
|
|
||||||
|
class MethodsRegistry implements ArrayAccess, Countable
|
||||||
|
{
|
||||||
|
protected $methods = [];
|
||||||
|
|
||||||
|
public function set(AbstractMethod $method)
|
||||||
|
{
|
||||||
|
$this->methods[$method->getName()] = clone $method;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unsetByName($name)
|
||||||
|
{
|
||||||
|
unset($this->methods[$name]);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $name
|
||||||
|
* @return AbstractMethod|null
|
||||||
|
*/
|
||||||
|
public function findByName($name)
|
||||||
|
{
|
||||||
|
return (isset($this->methods[$name]) and $this->methods[$name] instanceof AbstractMethod) ? $this->methods[$name] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetExists($offset): bool
|
||||||
|
{
|
||||||
|
return isset($this->methods[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetGet($offset): mixed
|
||||||
|
{
|
||||||
|
$m = $this->findByName($offset);
|
||||||
|
return $m ? $m->getArgumentCount() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetSet($offset, $value): void
|
||||||
|
{
|
||||||
|
throw new RuntimeException('Use set() method instead');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function offsetUnset($offset): void
|
||||||
|
{
|
||||||
|
$this->unsetByName($offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return count($this->methods);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
vendor/andileco/eval-math/src/Stack.php
vendored
Normal file
45
vendor/andileco/eval-math/src/Stack.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Stack
|
||||||
|
*/
|
||||||
|
class Stack
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $stack = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $count = 0;
|
||||||
|
|
||||||
|
public function push($val)
|
||||||
|
{
|
||||||
|
$this->stack[$this->count] = $val;
|
||||||
|
$this->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pop()
|
||||||
|
{
|
||||||
|
if ($this->count > 0) {
|
||||||
|
$this->count--;
|
||||||
|
return $this->stack[$this->count];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function last($n=1)
|
||||||
|
{
|
||||||
|
$key = $this->count - $n;
|
||||||
|
|
||||||
|
return array_key_exists($key,$this->stack) ? $this->stack[$key] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
216
vendor/andileco/eval-math/tests/EvalMathExceptionsTest.php
vendored
Normal file
216
vendor/andileco/eval-math/tests/EvalMathExceptionsTest.php
vendored
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Andileco\Util\EvalMath\EvalMath;
|
||||||
|
use Andileco\Util\EvalMath\Exception\AbstractEvalMathException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\BuiltInFunctionRedefinitionException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\ConstantAssignmentException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\DivisionByZeroException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\ExpectingTokenException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\IllegalCharacterException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\InternalErrorException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\InvalidArgumentCountException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\OperatorLacksOperandException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\OperatorRequiredException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UndefinedVariableException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UndefinedVariableInFunctionDefinitionException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UnexpectedOperatorException;
|
||||||
|
use Andileco\Util\EvalMath\Exception\UnexpectedTokenException;
|
||||||
|
|
||||||
|
class EvalMathExceptionsTest extends TestCase
|
||||||
|
{
|
||||||
|
private $EvalMath;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->EvalMath = new EvalMath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testBuiltInFunctionRedefinition()
|
||||||
|
{
|
||||||
|
$this->expectException(BuiltInFunctionRedefinitionException::class);
|
||||||
|
$this->EvalMath->evaluate('cos(x) = x*2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testConstantAssignmentException()
|
||||||
|
{
|
||||||
|
$this->expectException(ConstantAssignmentException::class);
|
||||||
|
$this->EvalMath->evaluate('pi = 123');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testDivisionByZero()
|
||||||
|
{
|
||||||
|
$this->expectException(DivisionByZeroException::class);
|
||||||
|
$this->EvalMath->evaluate('5/0');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testExpectingTokenException()
|
||||||
|
{
|
||||||
|
$this->expectException(ExpectingTokenException::class);
|
||||||
|
$this->EvalMath->evaluate('p = 6*(3+1');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testIllegalCharacterException()
|
||||||
|
{
|
||||||
|
$this->expectException(IllegalCharacterException::class);
|
||||||
|
$this->EvalMath->evaluate('$v = 5');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testInternalErrorException()
|
||||||
|
{
|
||||||
|
$this->expectException(InternalErrorException::class);
|
||||||
|
$this->EvalMath->e('k=');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testInvalidArgumentCountException()
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentCountException::class);
|
||||||
|
$this->EvalMath->e('a=sin(5,7,6)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testInvalidArgumentFuncCountException()
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentCountException::class);
|
||||||
|
$this->EvalMath->e('iif(1)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testInvalidArgumentFuncCountException2()
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentCountException::class);
|
||||||
|
$this->EvalMath->e('iif()');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testInvalidArgumentUserFuncCountException()
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentCountException::class);
|
||||||
|
$this->EvalMath->e('f(a,b) = a+b');
|
||||||
|
$this->EvalMath->e('f(1)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testOperatorLacksOperandException()
|
||||||
|
{
|
||||||
|
$this->expectException(OperatorLacksOperandException::class);
|
||||||
|
$this->EvalMath->e('k=5+');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testOperatorRequiredException()
|
||||||
|
{
|
||||||
|
$this->expectException(OperatorRequiredException::class);
|
||||||
|
$this->EvalMath->e('a=5(7+1)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUndefinedVariableException()
|
||||||
|
{
|
||||||
|
$this->expectException(UndefinedVariableException::class);
|
||||||
|
$this->EvalMath->e('b=a+1');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUndefinedVariableInFunctionDefinitionException()
|
||||||
|
{
|
||||||
|
$this->expectException(UndefinedVariableInFunctionDefinitionException::class);
|
||||||
|
$this->EvalMath->e('f(a) = b*3');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUnexpectedOperatorException()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedOperatorException::class);
|
||||||
|
$this->EvalMath->e('1 + * 2');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUnexpectedTokenException()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedTokenException::class);
|
||||||
|
$this->EvalMath->e('a=(3+)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUnexpectedClosingPrenticeException()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedTokenException::class);
|
||||||
|
$this->EvalMath->e('a=5)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUnexpectedComma()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedTokenException::class);
|
||||||
|
$this->EvalMath->e('a=5,3)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUnexpectedComma2()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedTokenException::class);
|
||||||
|
$this->EvalMath->e('a=sin(0.3),3)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws AbstractEvalMathException
|
||||||
|
*/
|
||||||
|
public function testUnexpectedComma3()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedTokenException::class);
|
||||||
|
$this->EvalMath->e('a=sin(0.1,)');
|
||||||
|
}
|
||||||
|
}
|
||||||
140
vendor/andileco/eval-math/tests/EvalMathTest.php
vendored
Normal file
140
vendor/andileco/eval-math/tests/EvalMathTest.php
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EvalMathTest.php
|
||||||
|
*
|
||||||
|
* @author dbojdo - Daniel Bojdo <daniel.bojdo@8x8.com>
|
||||||
|
* Created on 02 12, 2016, 17:17
|
||||||
|
* Copyright (C) 8x8
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Andileco\Util\EvalMath\EvalMath;
|
||||||
|
|
||||||
|
class EvalMathTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var EvalMath
|
||||||
|
*/
|
||||||
|
private $evalMath;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->evalMath = new EvalMath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @dataProvider moduloOperatorData
|
||||||
|
*/
|
||||||
|
public function shouldSupportModuloOperator($formula, $values, $expectedResult)
|
||||||
|
{
|
||||||
|
foreach ($values as $k => $v) {
|
||||||
|
$this->evalMath->v[$k] = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals($expectedResult, $this->evalMath->evaluate($formula));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moduloOperatorData()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array(
|
||||||
|
'a%b', // 9%3 => 0
|
||||||
|
array('a' => 9, 'b' => 3),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'a%b', // 10%3 => 1
|
||||||
|
array('a' => 10, 'b' => 3),
|
||||||
|
1
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'10-a%(b+c*d)', // 10-10%(7-2*2) => 9
|
||||||
|
array('a' => '10', 'b' => 7, 'c'=> -2, 'd' => 2),
|
||||||
|
9
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @dataProvider doubleMinusData
|
||||||
|
*/
|
||||||
|
public function shouldConsiderDoubleMinusAsPlus($formula, $values, $expectedResult)
|
||||||
|
{
|
||||||
|
foreach ($values as $k => $v) {
|
||||||
|
$this->evalMath->v[$k] = $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
$expectedResult,
|
||||||
|
$this->evalMath->evaluate($formula)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doubleMinusData()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array(
|
||||||
|
'a+b*c--d', // 1+2*3--4 => 1+6+4 => 11
|
||||||
|
array(
|
||||||
|
'a' => 1,
|
||||||
|
'b' => 2,
|
||||||
|
'c' => 3,
|
||||||
|
'd' => 4
|
||||||
|
),
|
||||||
|
11
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'a+b*c--d', // 1+2*3---4 => 1+6-4 => 3
|
||||||
|
array(
|
||||||
|
'a' => 1,
|
||||||
|
'b' => 2,
|
||||||
|
'c' => 3,
|
||||||
|
'd' => -4
|
||||||
|
),
|
||||||
|
3
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider maximumsData
|
||||||
|
*/
|
||||||
|
public function testMaxCalcFunction($formula, $expected)
|
||||||
|
{
|
||||||
|
$this->assertEquals($expected, $this->evalMath->e($formula));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function maximumsData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['max(1,2,3,4,5)', 5],
|
||||||
|
['max(5,2,3,1,4)', 5],
|
||||||
|
['max(5)', 5],
|
||||||
|
['max(5,5)', 5]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider comparisonsData
|
||||||
|
*/
|
||||||
|
public function testComparisonOperators($formula, $expected)
|
||||||
|
{
|
||||||
|
$this->assertEquals($expected, $this->evalMath->e($formula));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function comparisonsData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['1==1', 1],
|
||||||
|
['1==2', 0],
|
||||||
|
['1>2', 0],
|
||||||
|
['1<2', 1],
|
||||||
|
['1>=1', 1],
|
||||||
|
['1<=2', 1]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
63
vendor/andileco/eval-math/tests/MethodRegistryTest.php
vendored
Normal file
63
vendor/andileco/eval-math/tests/MethodRegistryTest.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Tests;
|
||||||
|
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use RuntimeException;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Maximum;
|
||||||
|
use Andileco\Util\EvalMath\MethodsRegistry;
|
||||||
|
|
||||||
|
class MethodRegistryTest extends TestCase
|
||||||
|
{
|
||||||
|
private $registry;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->registry = new MethodsRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetFindUnset()
|
||||||
|
{
|
||||||
|
$r = $this->registry->set(new Maximum);
|
||||||
|
$this->assertInstanceOf(MethodsRegistry::class, $r);
|
||||||
|
|
||||||
|
$c = $this->registry->findByName('max');
|
||||||
|
$this->assertInstanceOf(Maximum::class, $c);
|
||||||
|
$this->assertTrue(isset($this->registry['max']));
|
||||||
|
|
||||||
|
$c = $this->registry['max'];
|
||||||
|
$this->assertTrue(is_array($c));
|
||||||
|
// $this->assertInstanceOf(Maximum::class, $c);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $this->registry->count());
|
||||||
|
unset($this->registry['max']);
|
||||||
|
$this->assertEquals(0, $this->registry->count());
|
||||||
|
|
||||||
|
|
||||||
|
$r = $this->registry->unsetByName('max');
|
||||||
|
$this->assertInstanceOf(MethodsRegistry::class, $r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException RuntimeException
|
||||||
|
*/
|
||||||
|
public function testOffsetSetException()
|
||||||
|
{
|
||||||
|
$this->registry['max'] = new Maximum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAliases()
|
||||||
|
{
|
||||||
|
$this->registry = new MethodsRegistry();
|
||||||
|
$this->registry->set(new Maximum())->set((new Maximum)->setName('mmaaxx'));
|
||||||
|
$this->assertEquals(2, $this->registry->count());
|
||||||
|
$this->assertTrue(isset($this->registry['max']));
|
||||||
|
$this->assertTrue(isset($this->registry['mmaaxx']));
|
||||||
|
}
|
||||||
|
}
|
||||||
69
vendor/andileco/eval-math/tests/MethodsTest.php
vendored
Normal file
69
vendor/andileco/eval-math/tests/MethodsTest.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Conditional;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Maximum;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Minimum;
|
||||||
|
use Andileco\Util\EvalMath\Methods\Round;
|
||||||
|
|
||||||
|
class MethodsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testConditional()
|
||||||
|
{
|
||||||
|
$m = new Conditional();
|
||||||
|
$this->assertEquals('if', $m->getName());
|
||||||
|
$this->assertEquals([3], $m->getArgumentCount());
|
||||||
|
$this->assertEquals(1, $m->evaluate(true, 1, 0));
|
||||||
|
$this->assertEquals(0, $m->evaluate(false, 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMaximum()
|
||||||
|
{
|
||||||
|
$m = new Maximum();
|
||||||
|
$this->assertEquals('max', $m->getName());
|
||||||
|
$this->assertEquals([-1], $m->getArgumentCount());
|
||||||
|
$this->assertEquals(1, $m->evaluate(1, 0));
|
||||||
|
$this->assertEquals(10, $m->evaluate(false, 1, 0, 10));
|
||||||
|
$this->assertEquals(1, $m->evaluate(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMinimum()
|
||||||
|
{
|
||||||
|
$m = new Minimum();
|
||||||
|
$this->assertEquals('min', $m->getName());
|
||||||
|
$this->assertEquals([-1], $m->getArgumentCount());
|
||||||
|
$this->assertEquals(0, $m->evaluate(1, 0));
|
||||||
|
$this->assertEquals(0, $m->evaluate(false, 1, 0, 10));
|
||||||
|
$this->assertEquals(1, $m->evaluate(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRound()
|
||||||
|
{
|
||||||
|
$m = new Round();
|
||||||
|
$this->assertEquals('round', $m->getName());
|
||||||
|
$this->assertEquals([-1], $m->getArgumentCount());
|
||||||
|
|
||||||
|
$this->assertEquals(2, $m->evaluate(1.5321));
|
||||||
|
$this->assertEquals(1, $m->evaluate(1.4321));
|
||||||
|
$this->assertEquals(1, $m->evaluate(1.4921));
|
||||||
|
|
||||||
|
$this->assertEquals(git add .1.57, $m->evaluate(1.5678, 2));
|
||||||
|
$this->assertEquals(1.568, $m->evaluate(1.5678, 3));
|
||||||
|
$this->assertEquals(1.5678, $m->evaluate(1.5678, 4));
|
||||||
|
|
||||||
|
$this->assertEquals(1.54, $m->evaluate(1.5378, 2));
|
||||||
|
$this->assertEquals(1.538, $m->evaluate(1.5378, 3));
|
||||||
|
$this->assertEquals(1.5378, $m->evaluate(1.5378, 4));
|
||||||
|
|
||||||
|
$this->assertEquals(1.53, $m->evaluate(1.5321, 2));
|
||||||
|
$this->assertEquals(1.532, $m->evaluate(1.5321, 3));
|
||||||
|
$this->assertEquals(1.5321, $m->evaluate(1.5321, 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
24
vendor/andileco/eval-math/tests/UserFunctionsTest.php
vendored
Normal file
24
vendor/andileco/eval-math/tests/UserFunctionsTest.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Tests;
|
||||||
|
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Andileco\Util\EvalMath\EvalMath;
|
||||||
|
|
||||||
|
class UserFunctionsTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testFunctionsDump()
|
||||||
|
{
|
||||||
|
$e = new EvalMath();
|
||||||
|
$this->assertEmpty($e->funcs());
|
||||||
|
|
||||||
|
$e->e('f(x)=2*x');
|
||||||
|
$this->assertEquals(1, count($e->funcs()));
|
||||||
|
}
|
||||||
|
}
|
||||||
25
vendor/andileco/eval-math/tests/UserVariablesTest.php
vendored
Normal file
25
vendor/andileco/eval-math/tests/UserVariablesTest.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @author Serge Rodovnichenko <serge@syrnik.com>
|
||||||
|
* @copyright Serge Rodovnichenko, 2019
|
||||||
|
* @license BSD 2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Andileco\Util\EvalMath\Tests;
|
||||||
|
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Andileco\Util\EvalMath\EvalMath;
|
||||||
|
|
||||||
|
class UserVariablesTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testVariablesDump()
|
||||||
|
{
|
||||||
|
$e = new EvalMath();
|
||||||
|
$this->assertEmpty($e->vars());
|
||||||
|
|
||||||
|
$e->evaluate('a=1');
|
||||||
|
$this->assertArrayHasKey('a',$e->vars());
|
||||||
|
$this->assertEquals('1', $e->vars()['a']);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
vendor/composer/autoload_psr4.php
vendored
1
vendor/composer/autoload_psr4.php
vendored
@@ -120,4 +120,5 @@ return array(
|
|||||||
'Behat\\Mink\\Driver\\' => array($vendorDir . '/behat/mink-browserkit-driver/src', $vendorDir . '/behat/mink-selenium2-driver/src'),
|
'Behat\\Mink\\Driver\\' => array($vendorDir . '/behat/mink-browserkit-driver/src', $vendorDir . '/behat/mink-selenium2-driver/src'),
|
||||||
'Behat\\Mink\\' => array($vendorDir . '/behat/mink/src'),
|
'Behat\\Mink\\' => array($vendorDir . '/behat/mink/src'),
|
||||||
'Asm89\\Stack\\' => array($vendorDir . '/asm89/stack-cors/src'),
|
'Asm89\\Stack\\' => array($vendorDir . '/asm89/stack-cors/src'),
|
||||||
|
'Andileco\\Util\\EvalMath\\' => array($vendorDir . '/andileco/eval-math/src'),
|
||||||
);
|
);
|
||||||
|
|||||||
5
vendor/composer/autoload_static.php
vendored
5
vendor/composer/autoload_static.php
vendored
@@ -210,6 +210,7 @@ class ComposerStaticInit103f9b8db31610ca1687c620aeec857d
|
|||||||
'A' =>
|
'A' =>
|
||||||
array (
|
array (
|
||||||
'Asm89\\Stack\\' => 12,
|
'Asm89\\Stack\\' => 12,
|
||||||
|
'Andileco\\Util\\EvalMath\\' => 23,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -675,6 +676,10 @@ class ComposerStaticInit103f9b8db31610ca1687c620aeec857d
|
|||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/asm89/stack-cors/src',
|
0 => __DIR__ . '/..' . '/asm89/stack-cors/src',
|
||||||
),
|
),
|
||||||
|
'Andileco\\Util\\EvalMath\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/andileco/eval-math/src',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
public static $prefixesPsr0 = array (
|
public static $prefixesPsr0 = array (
|
||||||
|
|||||||
157
vendor/composer/installed.json
vendored
157
vendor/composer/installed.json
vendored
@@ -1,5 +1,54 @@
|
|||||||
{
|
{
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "andileco/eval-math",
|
||||||
|
"version": "3.0.1",
|
||||||
|
"version_normalized": "3.0.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/andileco/eval-math.git",
|
||||||
|
"reference": "52ff5728ad51961a630cc957328764cb02ab5c51"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/andileco/eval-math/zipball/52ff5728ad51961a630cc957328764cb02ab5c51",
|
||||||
|
"reference": "52ff5728ad51961a630cc957328764cb02ab5c51",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php-coveralls/php-coveralls": "^2",
|
||||||
|
"phpunit/phpunit": "^5"
|
||||||
|
},
|
||||||
|
"time": "2022-07-21T21:04:26+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Andileco\\Util\\EvalMath\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"description": "EvalMath",
|
||||||
|
"keywords": [
|
||||||
|
"EvalMath"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/andileco/eval-math/issues",
|
||||||
|
"source": "https://github.com/andileco/eval-math/tree/3.0.1"
|
||||||
|
},
|
||||||
|
"install-path": "../andileco/eval-math"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "asm89/stack-cors",
|
"name": "asm89/stack-cors",
|
||||||
"version": "v2.2.0",
|
"version": "v2.2.0",
|
||||||
@@ -1855,6 +1904,61 @@
|
|||||||
},
|
},
|
||||||
"install-path": "../../web/modules/admin_toolbar"
|
"install-path": "../../web/modules/admin_toolbar"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/charts",
|
||||||
|
"version": "5.1.1",
|
||||||
|
"version_normalized": "5.1.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/charts.git",
|
||||||
|
"reference": "5.1.1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/charts-5.1.1.zip",
|
||||||
|
"reference": "5.1.1",
|
||||||
|
"shasum": "81529ec926462ddc62e9f9f78d47b036af566b6b"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"drupal/core": "^10.3 || ^11"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"datestamp": "1733170631",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "andileco",
|
||||||
|
"homepage": "https://www.drupal.org/user/2054544"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nikathone",
|
||||||
|
"homepage": "https://www.drupal.org/user/2421800"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quicksketch",
|
||||||
|
"homepage": "https://www.drupal.org/user/35821"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A charting API for Drupal that provides chart elements and integration with Views.",
|
||||||
|
"homepage": "https://www.drupal.org/project/charts",
|
||||||
|
"support": {
|
||||||
|
"source": "https://git.drupalcode.org/project/charts"
|
||||||
|
},
|
||||||
|
"install-path": "../../web/modules/charts"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drupal/coder",
|
"name": "drupal/coder",
|
||||||
"version": "8.3.26",
|
"version": "8.3.26",
|
||||||
@@ -4111,6 +4215,59 @@
|
|||||||
},
|
},
|
||||||
"install-path": "../../web/modules/views_geojson"
|
"install-path": "../../web/modules/views_geojson"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "drupal/views_simple_math_field",
|
||||||
|
"version": "3.0.2",
|
||||||
|
"version_normalized": "3.0.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.drupalcode.org/project/views_simple_math_field.git",
|
||||||
|
"reference": "3.0.2"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://ftp.drupal.org/files/projects/views_simple_math_field-3.0.2.zip",
|
||||||
|
"reference": "3.0.2",
|
||||||
|
"shasum": "6620ee614bbaf68b9c26227e01c74299be47a6d8"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"andileco/eval-math": "^3.0.1",
|
||||||
|
"drupal/core": "^8.7|^9.0 || ^10 || ^11"
|
||||||
|
},
|
||||||
|
"type": "drupal-module",
|
||||||
|
"extra": {
|
||||||
|
"drupal": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"datestamp": "1719379402",
|
||||||
|
"security-coverage": {
|
||||||
|
"status": "covered",
|
||||||
|
"message": "Covered by Drupal's security advisory policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||||
|
"license": [
|
||||||
|
"GPL-2.0+"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "andileco",
|
||||||
|
"homepage": "https://www.drupal.org/user/2054544"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Beakerboy",
|
||||||
|
"homepage": "https://www.drupal.org/user/1700098"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Math operations over selected fields",
|
||||||
|
"homepage": "https://www.drupal.org/project/views_simple_math_field",
|
||||||
|
"support": {
|
||||||
|
"source": "http://cgit.drupalcode.org/views_simple_math_field",
|
||||||
|
"issues": "https://www.drupal.org/project/issues/views_simple_math_field"
|
||||||
|
},
|
||||||
|
"install-path": "../../web/modules/views_simple_math_field"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "drush/drush",
|
"name": "drush/drush",
|
||||||
"version": "12.5.3",
|
"version": "12.5.3",
|
||||||
|
|||||||
39
vendor/composer/installed.php
vendored
39
vendor/composer/installed.php
vendored
@@ -1,15 +1,24 @@
|
|||||||
<?php return array(
|
<?php return array(
|
||||||
'root' => array(
|
'root' => array(
|
||||||
'name' => 'farmos/project',
|
'name' => 'farmos/project',
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
'pretty_version' => 'dev-main',
|
||||||
'version' => '1.0.0.0',
|
'version' => 'dev-main',
|
||||||
'reference' => null,
|
'reference' => '62a5f3c97c55bae97ffe5b46a8cdb83a78581319',
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev' => true,
|
'dev' => true,
|
||||||
),
|
),
|
||||||
'versions' => array(
|
'versions' => array(
|
||||||
|
'andileco/eval-math' => array(
|
||||||
|
'pretty_version' => '3.0.1',
|
||||||
|
'version' => '3.0.1.0',
|
||||||
|
'reference' => '52ff5728ad51961a630cc957328764cb02ab5c51',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../andileco/eval-math',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'asm89/stack-cors' => array(
|
'asm89/stack-cors' => array(
|
||||||
'pretty_version' => 'v2.2.0',
|
'pretty_version' => 'v2.2.0',
|
||||||
'version' => '2.2.0.0',
|
'version' => '2.2.0.0',
|
||||||
@@ -244,6 +253,15 @@
|
|||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
|
'drupal/charts' => array(
|
||||||
|
'pretty_version' => '5.1.1',
|
||||||
|
'version' => '5.1.1.0',
|
||||||
|
'reference' => '5.1.1',
|
||||||
|
'type' => 'drupal-module',
|
||||||
|
'install_path' => __DIR__ . '/../../web/modules/charts',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'drupal/coder' => array(
|
'drupal/coder' => array(
|
||||||
'pretty_version' => '8.3.26',
|
'pretty_version' => '8.3.26',
|
||||||
'version' => '8.3.26.0',
|
'version' => '8.3.26.0',
|
||||||
@@ -685,6 +703,15 @@
|
|||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
|
'drupal/views_simple_math_field' => array(
|
||||||
|
'pretty_version' => '3.0.2',
|
||||||
|
'version' => '3.0.2.0',
|
||||||
|
'reference' => '3.0.2',
|
||||||
|
'type' => 'drupal-module',
|
||||||
|
'install_path' => __DIR__ . '/../../web/modules/views_simple_math_field',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'drush/drush' => array(
|
'drush/drush' => array(
|
||||||
'pretty_version' => '12.5.3',
|
'pretty_version' => '12.5.3',
|
||||||
'version' => '12.5.3.0',
|
'version' => '12.5.3.0',
|
||||||
@@ -740,9 +767,9 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'farmos/project' => array(
|
'farmos/project' => array(
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
'pretty_version' => 'dev-main',
|
||||||
'version' => '1.0.0.0',
|
'version' => 'dev-main',
|
||||||
'reference' => null,
|
'reference' => '62a5f3c97c55bae97ffe5b46a8cdb83a78581319',
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
|
|||||||
97
web/modules/charts/.gitlab-ci.yml
Normal file
97
web/modules/charts/.gitlab-ci.yml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
################
|
||||||
|
# DrupalCI GitLabCI template
|
||||||
|
#
|
||||||
|
# Gitlab-ci.yml to replicate DrupalCI testing for Contrib
|
||||||
|
#
|
||||||
|
# With thanks to:
|
||||||
|
# * The GitLab Acceleration Initiative participants
|
||||||
|
# * DrupalSpoons
|
||||||
|
################
|
||||||
|
|
||||||
|
################
|
||||||
|
# Guidelines
|
||||||
|
#
|
||||||
|
# This template is designed to give any Contrib maintainer everything they need to test, without requiring modification. It is also designed to keep up to date with Core Development automatically through the use of include files that can be centrally maintained.
|
||||||
|
#
|
||||||
|
# However, you can modify this template if you have additional needs for your project.
|
||||||
|
################
|
||||||
|
|
||||||
|
################
|
||||||
|
# Includes
|
||||||
|
#
|
||||||
|
# Additional configuration can be provided through includes.
|
||||||
|
# One advantage of include files is that if they are updated upstream, the changes affect all pipelines using that include.
|
||||||
|
#
|
||||||
|
# Includes can be overridden by re-declaring anything provided in an include, here in gitlab-ci.yml
|
||||||
|
# https://docs.gitlab.com/ee/ci/yaml/includes.html#override-included-configuration-values
|
||||||
|
################
|
||||||
|
|
||||||
|
include:
|
||||||
|
################
|
||||||
|
# DrupalCI includes:
|
||||||
|
# As long as you include this, any future includes added by the Drupal Association will be accessible to your pipelines automatically.
|
||||||
|
# View these include files at https://git.drupalcode.org/project/gitlab_templates/
|
||||||
|
################
|
||||||
|
- project: $_GITLAB_TEMPLATES_REPO
|
||||||
|
ref: $_GITLAB_TEMPLATES_REF
|
||||||
|
file:
|
||||||
|
- '/includes/include.drupalci.main.yml'
|
||||||
|
- '/includes/include.drupalci.variables.yml'
|
||||||
|
- '/includes/include.drupalci.workflows.yml'
|
||||||
|
|
||||||
|
################
|
||||||
|
# Pipeline configuration variables
|
||||||
|
#
|
||||||
|
# These are the variables provided to the Run Pipeline form that a user may want to override.
|
||||||
|
#
|
||||||
|
# Docs at https://git.drupalcode.org/project/gitlab_templates/-/blob/1.0.x/includes/include.drupalci.variables.yml
|
||||||
|
################
|
||||||
|
# variables:
|
||||||
|
# SKIP_ESLINT: '1'
|
||||||
|
|
||||||
|
|
||||||
|
###################################################################################
|
||||||
|
#
|
||||||
|
# *
|
||||||
|
# /(
|
||||||
|
# ((((,
|
||||||
|
# /(((((((
|
||||||
|
# ((((((((((*
|
||||||
|
# ,(((((((((((((((
|
||||||
|
# ,(((((((((((((((((((
|
||||||
|
# ((((((((((((((((((((((((*
|
||||||
|
# *(((((((((((((((((((((((((((((
|
||||||
|
# ((((((((((((((((((((((((((((((((((*
|
||||||
|
# *(((((((((((((((((( .((((((((((((((((((
|
||||||
|
# ((((((((((((((((((. /(((((((((((((((((*
|
||||||
|
# /((((((((((((((((( .(((((((((((((((((,
|
||||||
|
# ,(((((((((((((((((( ((((((((((((((((((
|
||||||
|
# .(((((((((((((((((((( .(((((((((((((((((
|
||||||
|
# ((((((((((((((((((((((( ((((((((((((((((/
|
||||||
|
# (((((((((((((((((((((((((((/ ,(((((((((((((((*
|
||||||
|
# .((((((((((((((/ /(((((((((((((. ,(((((((((((((((
|
||||||
|
# *(((((((((((((( ,(((((((((((((/ *((((((((((((((.
|
||||||
|
# ((((((((((((((, /(((((((((((((. ((((((((((((((,
|
||||||
|
# (((((((((((((/ ,(((((((((((((* ,(((((((((((((,
|
||||||
|
# *((((((((((((( .((((((((((((((( ,(((((((((((((
|
||||||
|
# ((((((((((((/ /((((((((((((((((((. ,((((((((((((/
|
||||||
|
# ((((((((((((( *(((((((((((((((((((((((* *((((((((((((
|
||||||
|
# ((((((((((((( ,(((((((((((((..((((((((((((( *((((((((((((
|
||||||
|
# ((((((((((((, /((((((((((((* /((((((((((((/ ((((((((((((
|
||||||
|
# ((((((((((((( /((((((((((((/ (((((((((((((* ((((((((((((
|
||||||
|
# (((((((((((((/ /(((((((((((( ,((((((((((((, *((((((((((((
|
||||||
|
# (((((((((((((( *(((((((((((/ *((((((((((((. ((((((((((((/
|
||||||
|
# *((((((((((((((((((((((((((, /(((((((((((((((((((((((((
|
||||||
|
# ((((((((((((((((((((((((( ((((((((((((((((((((((((,
|
||||||
|
# .(((((((((((((((((((((((/ ,(((((((((((((((((((((((
|
||||||
|
# ((((((((((((((((((((((/ ,(((((((((((((((((((((/
|
||||||
|
# *((((((((((((((((((((( (((((((((((((((((((((,
|
||||||
|
# ,(((((((((((((((((((((, ((((((((((((((((((((/
|
||||||
|
# ,(((((((((((((((((((((* /((((((((((((((((((((
|
||||||
|
# ((((((((((((((((((((((, ,/((((((((((((((((((((,
|
||||||
|
# ,(((((((((((((((((((((((((((((((((((((((((((((((((((
|
||||||
|
# .(((((((((((((((((((((((((((((((((((((((((((((
|
||||||
|
# .((((((((((((((((((((((((((((((((((((,.
|
||||||
|
# .,(((((((((((((((((((((((((.
|
||||||
|
#
|
||||||
|
###################################################################################
|
||||||
339
web/modules/charts/LICENSE.txt
Normal file
339
web/modules/charts/LICENSE.txt
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
242
web/modules/charts/README.md
Executable file
242
web/modules/charts/README.md
Executable file
@@ -0,0 +1,242 @@
|
|||||||
|
# Charts
|
||||||
|
|
||||||
|
Transform **data** into **information**. The Charts module for Drupal enables
|
||||||
|
you to build dynamic charts without needing to write a line of code. If you are
|
||||||
|
comfortable coding, you can use the Charts API to generate or update charts.
|
||||||
|
Instructions for creating charts are included below.
|
||||||
|
|
||||||
|
There are many charting libraries (also sometimes referred to as providers)
|
||||||
|
that you can find online. Each has their own benefits, drawbacks, and APIs. To
|
||||||
|
use one of them **without** this module, you would need to 1) be familiar with
|
||||||
|
the charting library's API, 2) add its JavaScript file(s) in your page, and 3)
|
||||||
|
write code for every chart you want to include. That's a lot of effort, and it
|
||||||
|
requires knowledge and access that many Drupal site builders will not have.
|
||||||
|
|
||||||
|
Charts is designed so that anyone who wants a chart on their site can have a
|
||||||
|
chart -- and be happy with it.
|
||||||
|
|
||||||
|
## How Does The Charts Module Work (Technically)?
|
||||||
|
|
||||||
|
The Charts module takes data and configuration from your site, and with the help
|
||||||
|
of a submodule, organizes it into a JSON object that is saved as an attribute
|
||||||
|
on an HTML element on your page; the JSON objected is handed to your selected
|
||||||
|
charting library, which renders it into a chart.
|
||||||
|
|
||||||
|
## Charting Providers / Libraries
|
||||||
|
|
||||||
|
Out of the box, you will be able to use 5 charting solutions (referred to as
|
||||||
|
"providers" or "libraries". Each of them has particular advantages and
|
||||||
|
disadvantages.
|
||||||
|
|
||||||
|
* Billboard.js: This library is a fork of the C3 charting library. It has
|
||||||
|
additional features, such as radar charts.
|
||||||
|
* C3.js: This library is a D3-based reusable chart library that makes it easy
|
||||||
|
to generate D3-based charts.
|
||||||
|
* Chart.js: This is a simple yet flexible JavaScript charting for designers &
|
||||||
|
developers.
|
||||||
|
* Google Charts: This library generates interactive charts using SVG and VML.
|
||||||
|
* Highcharts: This library is one of the premier solutions for generating
|
||||||
|
charts. Although it is very powerful and aesthetically pleasing with smooth
|
||||||
|
animations, it requires a commercial license. It's free for non-commercial
|
||||||
|
use. See http://www.highcharts.com
|
||||||
|
|
||||||
|
## Chart Types
|
||||||
|
|
||||||
|
Each charting library has its own set of chart types. The Charts module
|
||||||
|
focuses on chart types that are available in *most* of the libraries.
|
||||||
|
To avoid a confusing user interface, the Charts module no longer includes
|
||||||
|
chart types that are not supported by the selected library in the Chart
|
||||||
|
Type selection. For example, if you select the Chart.js library, you will
|
||||||
|
not see the "Gauge" chart type.
|
||||||
|
|
||||||
|
## Installing Libraries
|
||||||
|
|
||||||
|
All the Charts submodules default to using a content delivery network (CDN) to
|
||||||
|
pull in the necessary JavaScript files unless a local copy is present, or you
|
||||||
|
have disabled the CDN option on the "Charts configuration" page
|
||||||
|
(`/admin/config/content/charts`).
|
||||||
|
|
||||||
|
Below are a couple outlines for adding the libraries locally.
|
||||||
|
|
||||||
|
### Using Composer
|
||||||
|
|
||||||
|
1. Ensure that you have the `composer/installers` package installed.
|
||||||
|
2. Ensure you have an installer-paths for the drupal-library type. Such as in
|
||||||
|
the composer.json of
|
||||||
|
https://github.com/drupal-composer/drupal-project/blob/9.x/composer.json
|
||||||
|
3. In each submodule, there is a README.md file that has code to add to your
|
||||||
|
site's composer.json file.
|
||||||
|
4. After updating your project's composer.json file, run the 'composer require'
|
||||||
|
command specified in each submodule's README.md file. For example, if you are
|
||||||
|
using Google Charts, step three would mean adding:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "google/charts",
|
||||||
|
"version": "45",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "google_charts"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://www.gstatic.com/charts/loader.js",
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
to your project's composer.json, and then running:
|
||||||
|
`composer require --prefer-dist google/charts:45`
|
||||||
|
|
||||||
|
### Using Composer and wikimedia/composer-merge-plugin:
|
||||||
|
|
||||||
|
1. Ensure that you have the `wikimedia/composer-merge-plugin` package
|
||||||
|
installed.
|
||||||
|
2. Ensure that you have the `oomphinc/composer-installers-extender` package
|
||||||
|
installed.
|
||||||
|
3. Add an "installer-types" section in the "extra" of your project
|
||||||
|
composer.json file, make sure you have "npm-asset" listed. For example:
|
||||||
|
```json
|
||||||
|
"installer-types": [
|
||||||
|
"npm-asset"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
5. In the "installer-paths" section in the "extra" of your project
|
||||||
|
composer.json file, ensure you have the types drupal-library and npm-asset.
|
||||||
|
For example:
|
||||||
|
```json
|
||||||
|
"web/libraries/{$name}": [
|
||||||
|
"type:drupal-library",
|
||||||
|
"type:npm-asset"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
6. Add a "merge-plugin" section in the "extra" of your project composer.json
|
||||||
|
file, so that the composer.json file of the submodules you want is included.
|
||||||
|
For example:
|
||||||
|
```json
|
||||||
|
"merge-plugin": {
|
||||||
|
"include": [
|
||||||
|
"web/modules/contrib/charts/modules/charts_highcharts/composer.json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
```
|
||||||
|
7. Run the `composer require` specified in the submodule's README.md file
|
||||||
|
|
||||||
|
## Creating Charts in the UI
|
||||||
|
|
||||||
|
This module provides a configuration page at /admin/config/content/charts.
|
||||||
|
You may set site-wide defaults on this page (for example: set the default color
|
||||||
|
scheme). It also has library-specific configuration available after saving a
|
||||||
|
default library.
|
||||||
|
|
||||||
|
There are three options for creating a chart within the UI:
|
||||||
|
1. Using Views
|
||||||
|
2. Using a Chart Field
|
||||||
|
3. Using a Chart Block
|
||||||
|
|
||||||
|
### Creating Charts with Views
|
||||||
|
|
||||||
|
1. Create a new view:
|
||||||
|
Visit admin/structure/views/add and select the display format of "Chart" for
|
||||||
|
your new page or block.
|
||||||
|
|
||||||
|
2. Add a label field:
|
||||||
|
Under the "Fields" section, add a field you would like to be used as labels
|
||||||
|
along one axis of the chart (or slices of the pie). If you are visualizing
|
||||||
|
an Event content type, you might select `title`.
|
||||||
|
|
||||||
|
3. Add a data field or fields:
|
||||||
|
Now add a second field that will be used to determine the data values. If you
|
||||||
|
are visualizing an Event content type, this field might be
|
||||||
|
`field_number_attendees`. The label you give this field will be used in the
|
||||||
|
chart's legend to represent this series. Do this again for each different
|
||||||
|
quantity you would like to chart. Note that some chart types (e.g. "pie")
|
||||||
|
only support a single data column.
|
||||||
|
|
||||||
|
4. Configure the chart display:
|
||||||
|
Click on the "Settings" link in the "Format" section to configure the chart.
|
||||||
|
Select your chart library, type, the label field, and the data provider.
|
||||||
|
There are many other options to customize your chart. Some options may not
|
||||||
|
be available to all chart types and will be adjusted based on the type
|
||||||
|
selected.
|
||||||
|
|
||||||
|
5. Save your view.
|
||||||
|
|
||||||
|
As described in the steps above - if you have a field representing a number, you
|
||||||
|
do not necessarily need to aggregate your view. If the content you want to
|
||||||
|
visualize does not include a numeric field, you may need to aggregate your view
|
||||||
|
and use the `count` function to generate a number for your data field.
|
||||||
|
|
||||||
|
**Tip:** You may find it easier to start with a "Table" display and convert it
|
||||||
|
to a chart display after setting up the data. It can be easier to visualize
|
||||||
|
what the result of the chart will be if it's been laid out in a table first.
|
||||||
|
|
||||||
|
### Creating Combo Charts
|
||||||
|
|
||||||
|
If you are creating your chart in Views and want to a chart that includes
|
||||||
|
multiple chart types (such as columns and a line - aka a "combo" chart), add a
|
||||||
|
new display of type "Chart attachment". Use the middle column of this display
|
||||||
|
to attach the "Chart attachment" to a parent display (this is required). In
|
||||||
|
this section, you can also instruct the "Chart attachment" to inherit exposed
|
||||||
|
or contextual filters and if it should use the primary y-axis or a secondary
|
||||||
|
y-axis. You still need to configure the "Settings" in the "Format" section.
|
||||||
|
|
||||||
|
## Creating Charts in the UI with a Chart Field
|
||||||
|
|
||||||
|
If you want a chart in your entity (e.g. "node"), but don't need its data to be
|
||||||
|
dynamic (like Views could generate), you can use a Chart field. Add this field
|
||||||
|
to your bundle (e.g. "content type") via the "Manage Fields" tab - like you
|
||||||
|
would any other field. When you add a new entity, you can select the charting
|
||||||
|
library, chart type, and other configurations. You can add data using a CSV or
|
||||||
|
by manually adding it into the table input. The chart will show on your entity
|
||||||
|
after saving.
|
||||||
|
|
||||||
|
## Creating Charts in the UI with a Chart Block
|
||||||
|
|
||||||
|
If you are using Layout Builder or want to place a chart on several pages, and
|
||||||
|
the chart does not need dynamic data (like Views could generate), you can use a
|
||||||
|
Chart Block. When you add a Chart Block, you can select the charting library,
|
||||||
|
chart type, and other configurations. You can add data using a CSV or by
|
||||||
|
manually adding it into the table input.
|
||||||
|
|
||||||
|
## Creating Charts Using the API
|
||||||
|
|
||||||
|
Charts are elements that can be rendered using a Drupal render array. Please
|
||||||
|
refer to the `charts.api.php` file and also look at the included submodule,
|
||||||
|
`charts_api_examples` (specifically the controller, which has many examples).
|
||||||
|
|
||||||
|
## Debugging Your Charts
|
||||||
|
|
||||||
|
There is a checkbox in the "Advanced" tab of the config form
|
||||||
|
(/admin/config/content/charts/advanced) that enabled debugging. Checking this
|
||||||
|
box will enable a collapsible "details" element that includes the JSON
|
||||||
|
object generated by the Charts module - this can often be added directly
|
||||||
|
into a code playground provided by the charting library. If you are
|
||||||
|
implementing your own Charts submodule, you can add a line like this into
|
||||||
|
your charts_MYMODULE.js file (it may need modification):
|
||||||
|
```
|
||||||
|
if (element.nextElementSibling &&
|
||||||
|
element.nextElementSibling.hasAttribute('data-charts-debug-container')) {
|
||||||
|
element.nextElementSibling.querySelector('code').innerText = JSON.stringify(
|
||||||
|
config,
|
||||||
|
null,
|
||||||
|
' '
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For bug reports and feature requests please use the Drupal.org issue tracker:
|
||||||
|
https://www.drupal.org/project/issues/charts.
|
||||||
|
|
||||||
|
We welcome your support in improving code documentation, tests, and providing
|
||||||
|
example use-cases not addressed by the existing module.
|
||||||
|
|
||||||
|
If you are interested in creating your own submodule for a library not
|
||||||
|
currently supported, please contact
|
||||||
|
[@andileco](https://www.drupal.org/u/andileco).
|
||||||
174
web/modules/charts/charts.api.php
Normal file
174
web/modules/charts/charts.api.php
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Documentation on hooks provided by the Charts module.
|
||||||
|
*
|
||||||
|
* Charts module provides 4 element types that can be used to construct a chart.
|
||||||
|
* In its most basic form, a chart may be created by specifying an element
|
||||||
|
* with the #type property "chart". However, for enough information to
|
||||||
|
* accurately data to an audience, you need a little more. Below is a very
|
||||||
|
* basic example of a column chart.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* $chart = [
|
||||||
|
* '#type' => 'chart',
|
||||||
|
* '#chart_type' => 'column',
|
||||||
|
* 'series' => [
|
||||||
|
* '#type' => 'chart_data',
|
||||||
|
* '#title' => t('Responses'),
|
||||||
|
* '#data' => [60, 40],
|
||||||
|
* ],
|
||||||
|
* 'xaxis' => [
|
||||||
|
* '#type' => 'chart_xaxis',
|
||||||
|
* '#labels' => [t('Yes'), t('No')],
|
||||||
|
* ]
|
||||||
|
* ];
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* On charts that have multiple axes, you'll need to add individual sub-elements
|
||||||
|
* for each series of data. If you desire, you may also customize the axes by
|
||||||
|
* providing an axis element too.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* $chart = [
|
||||||
|
* '#type' => 'chart',
|
||||||
|
* '#chart_type' => 'column',
|
||||||
|
* ];
|
||||||
|
* $chart['series'] = [
|
||||||
|
* '#type' => 'chart_data',
|
||||||
|
* '#title' => t('Responses'),
|
||||||
|
* '#data' => [10, 20, 30],
|
||||||
|
* ];
|
||||||
|
* $chart['xaxis'] = [
|
||||||
|
* '#type' => 'chart_xaxis',
|
||||||
|
* '#title' => t('Month'),
|
||||||
|
* '#labels' => [t('Jan'), t('Feb'), t('Mar')],
|
||||||
|
* ];
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* Once you have generated a chart object, you can run
|
||||||
|
* \Drupal::service('renderer')->render() on it to turn it into HTML:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* $output = \Drupal::service('renderer')->render($chart);
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* There are many, many properties available for the four chart types (chart,
|
||||||
|
* chart_data, chart_xaxis, and chart_yaxis). For a full list, see the
|
||||||
|
* charts_element_info() function.
|
||||||
|
*
|
||||||
|
* This module also includes a number of examples for reference in the
|
||||||
|
* charts_api_example module, and displayed at /charts/example/display.
|
||||||
|
*
|
||||||
|
* @see Drupal\charts\Element folder
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter an individual chart before it is printed.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The chart renderable. Passed in by reference.
|
||||||
|
* @param string $chart_id
|
||||||
|
* The chart identifier, pulled from the $chart['#chart_id'] property
|
||||||
|
* (if any). Not all charts have a chart identifier.
|
||||||
|
*/
|
||||||
|
function hook_chart_alter(array &$element, $chart_id) {
|
||||||
|
if ($chart_id === 'view_name__display_name') {
|
||||||
|
// Individual properties may be modified.
|
||||||
|
$element['#title_font_size'] = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter an individual chart before it's rendered.
|
||||||
|
*
|
||||||
|
* Same as hook_chart_alter(), only including the $chart_id in the function
|
||||||
|
* name instead of being passed in as an argument.
|
||||||
|
*
|
||||||
|
* @see hook_chart_alter()
|
||||||
|
*/
|
||||||
|
function hook_chart_CHART_ID_alter(array &$element) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter an individual chart's raw library representation.
|
||||||
|
*
|
||||||
|
* This hook is called AFTER hook_chart_alter(), after Charts module has
|
||||||
|
* converted the renderable into the chart definition that will be used by the
|
||||||
|
* library. Note that the structure of $definition will differ based on the
|
||||||
|
* charting library used. Switching charting libraries may cause your code
|
||||||
|
* to break when using this hook.
|
||||||
|
*
|
||||||
|
* Even though this hook may be fragile, it may provide developers with access
|
||||||
|
* to library-specific functionality.
|
||||||
|
*
|
||||||
|
* @param array $definition
|
||||||
|
* The chart definition to be modified. The raw values are passed directly to
|
||||||
|
* the charting library.
|
||||||
|
* @param array $element
|
||||||
|
* The chart renderable. This may be used for reference (or read to add
|
||||||
|
* support for new properties), but any changes to this variable will not
|
||||||
|
* have an effect on output.
|
||||||
|
* @param string $chart_id
|
||||||
|
* The chart ID, derived from the $chart['#chart_id'] property. Note that not
|
||||||
|
* all charts may have a $chart_id.
|
||||||
|
*/
|
||||||
|
function hook_chart_definition_alter(array &$definition, array $element, $chart_id) {
|
||||||
|
if ($element['#chart_library'] === 'google') {
|
||||||
|
$definition['options']['titleTextStyle']['fontSize'] = 20;
|
||||||
|
}
|
||||||
|
elseif ($element['#chart_library'] === 'highcharts') {
|
||||||
|
$definition['title']['style']['fontSize'] = 20;
|
||||||
|
// Add a caption based on a field on your node containing a Chart field.
|
||||||
|
$node = $element['#entity'];
|
||||||
|
if ($node instanceof \Drupal\node\NodeInterface && $node->hasField('field_caption')) {
|
||||||
|
$definition['caption']['text'] = $node->field_caption->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter an individual chart before it's rendered.
|
||||||
|
*
|
||||||
|
* Same as hook_chart_definition_alter(), only including the $chart_id in the
|
||||||
|
* function name instead of being passed in as an argument.
|
||||||
|
*
|
||||||
|
* @see hook_chart_definition_alter()
|
||||||
|
*/
|
||||||
|
function hook_chart_definition_CHART_ID_alter(array &$definition, array $element, $chart_id) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alter the list of supported chart types for a chart plugin.
|
||||||
|
*
|
||||||
|
* To use this hook, first define the chart types you want to add in a file
|
||||||
|
* named <module>.charts_types.yml to your module's root directory. For example,
|
||||||
|
* if your module is named "charts_foo", the file should be named
|
||||||
|
* "charts_foo.charts_types.yml".
|
||||||
|
*
|
||||||
|
* The contents of this file will look something like:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* candlestick:
|
||||||
|
* label: 'Candlestick'
|
||||||
|
* axis: 'xy'
|
||||||
|
* axis_inverted: false
|
||||||
|
* stacking: false
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @see charts.charts_types.yml
|
||||||
|
*
|
||||||
|
* With that file in place, you can now implement this hook. See below for an
|
||||||
|
* example adding the 'candlestick' chart type to the 'highcharts' chart plugin.
|
||||||
|
*
|
||||||
|
* @param array $types
|
||||||
|
* An array of supported chart types.
|
||||||
|
* @param string $chart_plugin_id
|
||||||
|
* The chart plugin ID.
|
||||||
|
*/
|
||||||
|
function hook_charts_plugin_supported_chart_types_alter(array &$types, string $chart_plugin_id) {
|
||||||
|
if ($chart_plugin_id === 'highcharts') {
|
||||||
|
$types[] = 'candlestick';
|
||||||
|
}
|
||||||
|
}
|
||||||
50
web/modules/charts/charts.charts_types.yml
Executable file
50
web/modules/charts/charts.charts_types.yml
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
area:
|
||||||
|
label: 'Area'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: true
|
||||||
|
bar:
|
||||||
|
label: 'Bar'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: true
|
||||||
|
stacking: true
|
||||||
|
bubble:
|
||||||
|
label: 'Bubble'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
|
column:
|
||||||
|
label: 'Column'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: true
|
||||||
|
donut:
|
||||||
|
label: 'Donut'
|
||||||
|
axis: 'y_only'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
|
gauge:
|
||||||
|
label: 'Gauge'
|
||||||
|
axis: 'y_only'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
|
line:
|
||||||
|
label: 'Line'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
|
pie:
|
||||||
|
label: 'Pie'
|
||||||
|
axis: 'y_only'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
|
scatter:
|
||||||
|
label: 'Scatter'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
|
spline:
|
||||||
|
label: 'Spline'
|
||||||
|
axis: 'xy'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
5
web/modules/charts/charts.config_translation.yml
Normal file
5
web/modules/charts/charts.config_translation.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
charts.settings:
|
||||||
|
title: 'Charts settings'
|
||||||
|
base_route_name: charts.settings
|
||||||
|
names:
|
||||||
|
- charts.settings
|
||||||
11
web/modules/charts/charts.info.yml
Normal file
11
web/modules/charts/charts.info.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
name: Charts
|
||||||
|
type: module
|
||||||
|
description: 'A charting API for Drupal that provides chart elements and integration with Views.'
|
||||||
|
package: Charts
|
||||||
|
core_version_requirement: ^10.3 || ^11
|
||||||
|
configure: charts.settings
|
||||||
|
|
||||||
|
# Information added by Drupal.org packaging script on 2024-12-02
|
||||||
|
version: '5.1.1'
|
||||||
|
project: 'charts'
|
||||||
|
datestamp: 1733170633
|
||||||
15
web/modules/charts/charts.install
Executable file
15
web/modules/charts/charts.install
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Install and update functions for the Charts module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_requirements().
|
||||||
|
*/
|
||||||
|
function charts_requirements($phase) {
|
||||||
|
$requirements = [];
|
||||||
|
|
||||||
|
return $requirements;
|
||||||
|
}
|
||||||
7
web/modules/charts/charts.libraries.yml
Normal file
7
web/modules/charts/charts.libraries.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
global:
|
||||||
|
version: VERSION
|
||||||
|
js:
|
||||||
|
js/charts.js: {}
|
||||||
|
dependencies:
|
||||||
|
- core/drupal
|
||||||
5
web/modules/charts/charts.links.menu.yml
Executable file
5
web/modules/charts/charts.links.menu.yml
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
charts.settings:
|
||||||
|
title: 'Charts configuration'
|
||||||
|
description: 'Set the default library, behavior, and style of charts.'
|
||||||
|
parent: system.admin_config_content
|
||||||
|
route_name: charts.settings
|
||||||
16
web/modules/charts/charts.links.task.yml
Executable file
16
web/modules/charts/charts.links.task.yml
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
charts.settings:
|
||||||
|
title: 'Charts Settings'
|
||||||
|
route_name: charts.settings
|
||||||
|
base_route: charts.settings
|
||||||
|
|
||||||
|
charts.settings.default:
|
||||||
|
title: 'Default'
|
||||||
|
route_name: charts.settings
|
||||||
|
parent_id: charts.settings
|
||||||
|
weight: 10
|
||||||
|
|
||||||
|
charts.settings.advanced:
|
||||||
|
title: 'Advanced'
|
||||||
|
route_name: charts.settings.advanced
|
||||||
|
parent_id: charts.settings
|
||||||
|
weight: 20
|
||||||
230
web/modules/charts/charts.module
Executable file
230
web/modules/charts/charts.module
Executable file
@@ -0,0 +1,230 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Charts - Module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Drupal\views\ViewExecutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_views_data().
|
||||||
|
*/
|
||||||
|
function charts_views_data() {
|
||||||
|
$data['charts_fields']['table']['group'] = t('Charts');
|
||||||
|
$data['charts_fields']['table']['join'] = [
|
||||||
|
// Exist in all views.
|
||||||
|
'#global' => [],
|
||||||
|
];
|
||||||
|
$data['charts_fields']['field_charts_fields_scatter'] = [
|
||||||
|
'title' => t('Scatter Field'),
|
||||||
|
'help' => t('Use this field for your data field in a scatter plot.'),
|
||||||
|
'field' => [
|
||||||
|
'id' => 'field_charts_fields_scatter',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$data['charts_fields']['field_charts_fields_bubble'] = [
|
||||||
|
'title' => t('Bubble Field'),
|
||||||
|
'help' => t('Use this field for your data field in a bubble chart.'),
|
||||||
|
'field' => [
|
||||||
|
'id' => 'field_charts_fields_bubble',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$data['charts_fields']['field_exposed_chart_type'] = [
|
||||||
|
'title' => t('Exposed Chart Type'),
|
||||||
|
'help' => t('Use this field for exposing chart type.'),
|
||||||
|
'field' => [
|
||||||
|
'id' => 'field_exposed_chart_type',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_theme().
|
||||||
|
*/
|
||||||
|
function charts_theme($existing, $type, $theme, $path) {
|
||||||
|
return [
|
||||||
|
'charts_chart' => [
|
||||||
|
'render element' => 'element',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_preprocess_HOOK().
|
||||||
|
*/
|
||||||
|
function template_preprocess_charts_chart(&$variables) {
|
||||||
|
$element = $variables['element'];
|
||||||
|
|
||||||
|
$attributes = $element['#attributes'];
|
||||||
|
$attributes['id'] = $element['#id'];
|
||||||
|
$attributes['class'][] = 'chart';
|
||||||
|
|
||||||
|
$variables['content'] = [
|
||||||
|
'#type' => 'html_tag',
|
||||||
|
'#tag' => 'div',
|
||||||
|
'#attributes' => $attributes,
|
||||||
|
'#value' => $element['#chart'] ?? '',
|
||||||
|
];
|
||||||
|
$variables['content_prefix'] = $element['#content_prefix'];
|
||||||
|
$variables['content_suffix'] = $element['#content_suffix'];
|
||||||
|
$config = \Drupal::config('charts.settings');
|
||||||
|
$variables['debug'] = [];
|
||||||
|
if (!empty($config->get('advanced.debug'))) {
|
||||||
|
$variables['debug'] = [
|
||||||
|
'#type' => 'details',
|
||||||
|
'#title' => t('Chart JSON'),
|
||||||
|
'#open' => FALSE,
|
||||||
|
'#attributes' => [
|
||||||
|
'data-charts-debug-container' => TRUE,
|
||||||
|
],
|
||||||
|
'#collapsible' => TRUE,
|
||||||
|
'json' => [
|
||||||
|
'#prefix' => '<pre class="language-json">',
|
||||||
|
'#type' => 'html_tag',
|
||||||
|
'#tag' => 'code',
|
||||||
|
'#attributes' => [
|
||||||
|
'class' => ['language-json'],
|
||||||
|
],
|
||||||
|
'#value' => t('If this is blank, your library will need to implement code in your JavaScript. Please see the README.md.'),
|
||||||
|
'#suffix' => '</pre>',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_views_pre_view().
|
||||||
|
*/
|
||||||
|
function charts_views_pre_view(ViewExecutable $view, $display_id, array &$args) {
|
||||||
|
$hasFields = array_key_exists('fields', $view->display_handler->options);
|
||||||
|
if ($hasFields) {
|
||||||
|
$fields = $view->display_handler->getOption('fields');
|
||||||
|
$hasViewsFieldsOnOffHandler = FALSE;
|
||||||
|
foreach ($fields as $field) {
|
||||||
|
if (array_key_exists('plugin_id', $field)) {
|
||||||
|
|
||||||
|
if ($field['plugin_id'] == 'field_exposed_chart_type') {
|
||||||
|
$hasViewsFieldsOnOffHandler = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($hasViewsFieldsOnOffHandler) {
|
||||||
|
// Grab the type that has been submitted.
|
||||||
|
$params = \Drupal::request()->query->all();
|
||||||
|
// This is for a GET request.
|
||||||
|
// If the view is submitted through AJAX, like in view preview, it will be
|
||||||
|
// a POST request. Merge the parameter arrays and we will get our values.
|
||||||
|
$postParams = \Drupal::request()->request->all();
|
||||||
|
$params = array_merge($params, $postParams);
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
if (strpos($key, 'ct') === 0) {
|
||||||
|
$view->storage->set('exposed_chart_type', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$view->element['#cache']['contexts'][] = 'url';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_library_info_alter().
|
||||||
|
*
|
||||||
|
* Adapted from webform_library_info_alter() to add CDN support.
|
||||||
|
*/
|
||||||
|
function charts_library_info_alter(&$libraries, $extension) {
|
||||||
|
// Only process for charts_* modules.
|
||||||
|
if (strpos($extension, 'charts_') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only try to apply cdn changes if the cdn requirements is on.
|
||||||
|
$config = \Drupal::config('charts.settings');
|
||||||
|
if (!$config->get('advanced.requirements.cdn')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($libraries as &$library) {
|
||||||
|
if (isset($library['cdn']) && is_array($library['cdn'])) {
|
||||||
|
_charts_library_info_alter_recursive($library, $library['cdn']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive through a charts library.
|
||||||
|
*
|
||||||
|
* @param array $library
|
||||||
|
* A library defined in a chart module.
|
||||||
|
* @param array $cdn
|
||||||
|
* A associative array of library paths mapped to CDN URL.
|
||||||
|
*
|
||||||
|
* @note copied from _webform_library_info_alter_recursive().
|
||||||
|
*/
|
||||||
|
function _charts_library_info_alter_recursive(array &$library, array $cdn) {
|
||||||
|
foreach ($library as $key => &$value) {
|
||||||
|
// CSS and JS files and listed in associative arrays keyed via string.
|
||||||
|
if (!is_string($key) || !is_array($value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore the CDN's associative array.
|
||||||
|
if ($key === 'cdn') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the CDN sources (i.e. /library/*) with the CDN URL destination
|
||||||
|
// (https://cdnjs.cloudflare.com/ajax/libs/*).
|
||||||
|
foreach ($cdn as $source => $destination) {
|
||||||
|
if (_charts_library_check_source_exists($source)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strpos($key, $source) === 0) {
|
||||||
|
$uri = str_replace($source, $destination, $key);
|
||||||
|
$library[$uri] = $value;
|
||||||
|
$library[$uri]['type'] = 'external';
|
||||||
|
unset($library[$key]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse downward to find nested libraries.
|
||||||
|
_charts_library_info_alter_recursive($value, $cdn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a library source directory or file exists locally.
|
||||||
|
*
|
||||||
|
* @param string $source
|
||||||
|
* The source directory or file.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* True when the file exist, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
function _charts_library_check_source_exists(string $source) {
|
||||||
|
$source = rtrim($source, '/');
|
||||||
|
|
||||||
|
$container = \Drupal::getContainer();
|
||||||
|
$app_root = $container->getParameter('app.root');
|
||||||
|
$site_path = $container->getParameter('site.path');
|
||||||
|
|
||||||
|
// The following logic is taken from libraries_get_libraries()
|
||||||
|
$search_dir = [];
|
||||||
|
$search_dir[] = $app_root;
|
||||||
|
// Similar to 'modules' and 'themes' directories inside an installation
|
||||||
|
// profile, installation profiles may want to place libraries into a
|
||||||
|
// 'libraries' directory.
|
||||||
|
$search_dir[] = 'profiles/' . \Drupal::installProfile();
|
||||||
|
// Also search sites/<domain>/*.
|
||||||
|
$search_dir[] = $site_path;
|
||||||
|
|
||||||
|
foreach ($search_dir as $dir) {
|
||||||
|
if (file_exists($dir . $source) || file_exists($dir . $source)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
4
web/modules/charts/charts.permissions.yml
Executable file
4
web/modules/charts/charts.permissions.yml
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
'access all charts':
|
||||||
|
title: 'Administer Charts'
|
||||||
|
description: 'This permission needs to be fleshed out.'
|
||||||
|
'restrict access': true
|
||||||
221
web/modules/charts/charts.post_update.php
Normal file
221
web/modules/charts/charts.post_update.php
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Charts post-update file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Drupal\charts\ConfigUpdater;
|
||||||
|
use Drupal\Component\Serialization\Yaml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize advanced requirements cdn config value.
|
||||||
|
*/
|
||||||
|
function charts_post_update_initialize_advanced_requirements_cdn(&$sandbox) {
|
||||||
|
$config = \Drupal::service('config.factory')
|
||||||
|
->getEditable('charts.settings');
|
||||||
|
|
||||||
|
if ($config) {
|
||||||
|
$config->set('advanced', ['requirements' => ['cdn' => TRUE]]);
|
||||||
|
$config->save();
|
||||||
|
return 'Successfully initialized the advanced.requirements.cdn option.';
|
||||||
|
}
|
||||||
|
return 'No initialization was done. Please check your current config.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the existing default config display colors to increase from 10 to 25.
|
||||||
|
*/
|
||||||
|
function charts_post_update_existing_default_colors_to_twenty_five(&$sandbox) {
|
||||||
|
$config = \Drupal::service('config.factory')->getEditable('charts.settings');
|
||||||
|
$existing_colors = $config->get('charts_default_settings.display.colors');
|
||||||
|
|
||||||
|
if (is_countable($existing_colors) && count($existing_colors) === 10) {
|
||||||
|
$path = \Drupal::service('extension.list.module')->getPath('charts');
|
||||||
|
$default_install_settings_file = $path . '/config/install/charts.settings.yml';
|
||||||
|
if (!file_exists($default_install_settings_file)) {
|
||||||
|
return 'Failed to update the default colors to 25 because we could not load the charts settings.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$default_install_settings = Yaml::decode(file_get_contents($default_install_settings_file));
|
||||||
|
$install_colors = $default_install_settings['charts_default_settings']['display']['colors'];
|
||||||
|
// We only want to add the last 15 colors to make it 25.
|
||||||
|
$colors = array_merge($existing_colors, array_slice($install_colors, -15));
|
||||||
|
$config->set('charts_default_settings.display.colors', $colors);
|
||||||
|
$config->save();
|
||||||
|
return 'Successfully increased the number of default colors to 25.';
|
||||||
|
}
|
||||||
|
return 'We were unable to load existing colors in order to increased them to 25.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the config value for the debug setting.
|
||||||
|
*/
|
||||||
|
function charts_post_update_initialize_debug_option(&$sandbox) {
|
||||||
|
$config = \Drupal::service('config.factory')
|
||||||
|
->getEditable('charts.settings');
|
||||||
|
|
||||||
|
if ($config) {
|
||||||
|
$config->set('advanced.debug', FALSE);
|
||||||
|
$config->save();
|
||||||
|
return 'Successfully initialized the advanced.debug option.';
|
||||||
|
}
|
||||||
|
return 'No initialization was done. Please check your current config.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate library default settings to library_config key.
|
||||||
|
*/
|
||||||
|
function charts_post_update_migrate_library_default_settings_to_library_config(&$sandbox) {
|
||||||
|
/** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
|
||||||
|
$config_factory = \Drupal::service('config.factory');
|
||||||
|
$config = $config_factory->getEditable('charts.settings');
|
||||||
|
|
||||||
|
if ($config) {
|
||||||
|
$default_settings = $config->get('charts_default_settings');
|
||||||
|
$library_id = $default_settings['library'] ?? '';
|
||||||
|
$old_key = $library_id ? 'charts_default_settings.' . $library_id . '_settings' : '';
|
||||||
|
if ($old_key && empty($default_settings['display']) && $library_config = $config->get($old_key)) {
|
||||||
|
$config->set('charts_default_settings.library_config', $library_config);
|
||||||
|
$config->clear($old_key);
|
||||||
|
$config->save();
|
||||||
|
return 'Library default settings have been successfully migrated to library_config key.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'No migration was done';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear library_config set on the wrong place. See drupal.org/i/3310145.
|
||||||
|
*/
|
||||||
|
function charts_post_update_clear_library_config_key_added_on_wrong_place(&$sandbox) {
|
||||||
|
/** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
|
||||||
|
$config_factory = \Drupal::service('config.factory');
|
||||||
|
$config = $config_factory->getEditable('charts.settings');
|
||||||
|
if ($config && $config->get('library_config')) {
|
||||||
|
// Not to be confused with "charts_default_settings.library_config" which is
|
||||||
|
// the proper key.
|
||||||
|
$config->clear('library_config');
|
||||||
|
$config->save();
|
||||||
|
return 'Successfully cleared the library_config key.';
|
||||||
|
}
|
||||||
|
return 'The library_config key was not cleared, probably because it was not set.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates charts config and views with charts style of version 3 to new config.
|
||||||
|
*/
|
||||||
|
function charts_post_update_00_update_charts_version_3_to_latest_settings_structure(&$sandbox) {
|
||||||
|
/** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
|
||||||
|
$config_factory = \Drupal::service('config.factory');
|
||||||
|
$config = $config_factory->getEditable('charts.settings');
|
||||||
|
$default_settings = $config ? $config->get('charts_default_settings') : [];
|
||||||
|
|
||||||
|
/** @var \Drupal\charts\ConfigUpdater $config_updater */
|
||||||
|
$config_updater = \Drupal::classResolver(ConfigUpdater::class);
|
||||||
|
if ($default_settings && !isset($default_settings['display'])) {
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
$config->set('charts_default_settings', $config_updater->transformVersion3SettingsToNew($default_settings));
|
||||||
|
$config->save();
|
||||||
|
$results[] = 'Default Config: Migration to the new structure successfully done.';
|
||||||
|
|
||||||
|
$results[] = $config_updater->updateExistingViewsVersion3ToNewSettings();
|
||||||
|
return implode(' -- ', $results);
|
||||||
|
}
|
||||||
|
elseif (!$default_settings || !$config->getRawData()) {
|
||||||
|
$config->setData($config_updater->initializedCurrentDefaultSettings());
|
||||||
|
$config->save();
|
||||||
|
|
||||||
|
$results = [];
|
||||||
|
$results[] = 'Default Config: No config were found and the default one was saved.';
|
||||||
|
$results[] = $config_updater->updateExistingViewsVersion3ToNewSettings();
|
||||||
|
return implode(' -- ', $results);
|
||||||
|
}
|
||||||
|
return 'No update of the settings structure was done.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-save views that are using the chart style to recalculate dependencies.
|
||||||
|
*/
|
||||||
|
function charts_post_update_resave_views_to_account_calculated_library_dependencies(&$sandbox) {
|
||||||
|
$view_storage = \Drupal::entityTypeManager()->getStorage('view');
|
||||||
|
$view_ids = $view_storage->getQuery()
|
||||||
|
->accessCheck(FALSE)
|
||||||
|
->condition('display.*.display_options.style.type', 'chart', '=')
|
||||||
|
->execute();
|
||||||
|
$labels = [];
|
||||||
|
if ($view_ids) {
|
||||||
|
foreach ($view_ids as $view_id) {
|
||||||
|
/** @var \Drupal\views\ViewEntityInterface $view */
|
||||||
|
$view = $view_storage->load($view_id);
|
||||||
|
// Re-save the view to update its dependencies.
|
||||||
|
$view->save();
|
||||||
|
$labels[] = $view->label();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($labels) {
|
||||||
|
return t('The following views have been re-saved to re-calculate their dependencies: @views', [
|
||||||
|
'@views' => implode(',', $labels),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return t('This site did not have any chart related views.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting charts config module dependencies based on the selected library.
|
||||||
|
*/
|
||||||
|
function charts_post_update_setting_charts_config_module_dependencies(&$sandbox) {
|
||||||
|
$config = \Drupal::service('config.factory')
|
||||||
|
->getEditable('charts.settings');
|
||||||
|
$settings = $config->get('charts_default_settings');
|
||||||
|
$library = $settings['library'] ?? '';
|
||||||
|
$type = $settings['type'] ?? '';
|
||||||
|
if ($library || $type) {
|
||||||
|
/** @var \Drupal\charts\EventSubscriber\ConfigImportSubscriber $config_import_subscriber */
|
||||||
|
$config_import_subscriber = \Drupal::service('charts.config_import_subscriber');
|
||||||
|
$config->set('dependencies', $config_import_subscriber->calculateDependencies($library, $type))
|
||||||
|
->save();
|
||||||
|
return 'Updated chart settings dependencies';
|
||||||
|
}
|
||||||
|
return 'The default config for charts did not have a library and type set. So no dependencies were set.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move color changer from fields to display.
|
||||||
|
*/
|
||||||
|
function charts_post_update_move_views_style_color_changer_from_fields_to_display(&$sandbox) {
|
||||||
|
$view_storage = \Drupal::entityTypeManager()->getStorage('view');
|
||||||
|
$view_ids = $view_storage->getQuery()
|
||||||
|
->accessCheck(FALSE)
|
||||||
|
->condition('display.*.display_options.style.type', 'chart', '=')
|
||||||
|
->execute();
|
||||||
|
$labels = [];
|
||||||
|
if ($view_ids) {
|
||||||
|
foreach ($view_ids as $view_id) {
|
||||||
|
/** @var \Drupal\views\ViewEntityInterface $view */
|
||||||
|
$view = $view_storage->load($view_id);
|
||||||
|
$changed = FALSE;
|
||||||
|
foreach (array_keys($view->get('display')) as $display_id) {
|
||||||
|
$display = &$view->getDisplay($display_id);
|
||||||
|
if (isset($display['display_options']['style']['options']['chart_settings']['fields']['color_changer'])) {
|
||||||
|
$changed = TRUE;
|
||||||
|
$display['display_options']['style']['options']['chart_settings']['display']['color_changer'] = !empty($display['display_options']['style']['options']['chart_settings']['fields']['color_changer']);
|
||||||
|
unset($display['display_options']['style']['options']['chart_settings']['fields']['color_changer']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($changed) {
|
||||||
|
$view->save();
|
||||||
|
$labels[] = $view->label();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($labels) {
|
||||||
|
return t('The following views have been updated to move the color changer from fields to display: @views', [
|
||||||
|
'@views' => implode(',', $labels),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return t('This site did not have any chart related views.');
|
||||||
|
}
|
||||||
15
web/modules/charts/charts.routing.yml
Executable file
15
web/modules/charts/charts.routing.yml
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
charts.settings:
|
||||||
|
path: /admin/config/content/charts
|
||||||
|
defaults:
|
||||||
|
_form: Drupal\charts\Form\ChartsConfigForm
|
||||||
|
_title: 'Chart configuration'
|
||||||
|
requirements:
|
||||||
|
_permission: 'administer site configuration'
|
||||||
|
|
||||||
|
charts.settings.advanced:
|
||||||
|
path: /admin/config/content/charts/advanced
|
||||||
|
defaults:
|
||||||
|
_form: Drupal\charts\Form\ChartsConfigAdvancedForm
|
||||||
|
_title: 'Chart advanced configuration form'
|
||||||
|
requirements:
|
||||||
|
_permission: 'administer site configuration'
|
||||||
21
web/modules/charts/charts.services.yml
Executable file
21
web/modules/charts/charts.services.yml
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
services:
|
||||||
|
plugin.manager.charts:
|
||||||
|
class: Drupal\charts\ChartManager
|
||||||
|
parent: default_plugin_manager
|
||||||
|
|
||||||
|
plugin.manager.charts_type:
|
||||||
|
class: Drupal\charts\TypeManager
|
||||||
|
arguments: ['@module_handler', '@cache.discovery', '@event_dispatcher']
|
||||||
|
|
||||||
|
charts.plugins_uninstall_validator:
|
||||||
|
class: Drupal\charts\PluginsUninstallValidator
|
||||||
|
tags:
|
||||||
|
- { name: module_install.uninstall_validator }
|
||||||
|
arguments: ['@config.factory']
|
||||||
|
lazy: true
|
||||||
|
|
||||||
|
charts.config_import_subscriber:
|
||||||
|
class: Drupal\charts\EventSubscriber\ConfigImportSubscriber
|
||||||
|
arguments: ['@plugin.manager.charts', '@plugin.manager.charts_type']
|
||||||
|
tags:
|
||||||
|
- { name: event_subscriber }
|
||||||
0
web/modules/charts/charts.settings.yml
Executable file
0
web/modules/charts/charts.settings.yml
Executable file
73
web/modules/charts/config/install/charts.settings.yml
Normal file
73
web/modules/charts/config/install/charts.settings.yml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
dependencies: []
|
||||||
|
charts_default_settings:
|
||||||
|
library: ''
|
||||||
|
type: line
|
||||||
|
display:
|
||||||
|
title: ''
|
||||||
|
subtitle: ''
|
||||||
|
colors:
|
||||||
|
- '#006fb0'
|
||||||
|
- '#f07c33'
|
||||||
|
- '#342e9c'
|
||||||
|
- '#579b17'
|
||||||
|
- '#3f067a'
|
||||||
|
- '#cbde67'
|
||||||
|
- '#7643b6'
|
||||||
|
- '#738d00'
|
||||||
|
- '#c157c7'
|
||||||
|
- '#02dab1'
|
||||||
|
- '#ed56b4'
|
||||||
|
- '#d8d981'
|
||||||
|
- '#004695'
|
||||||
|
- '#736000'
|
||||||
|
- '#a5a5ff'
|
||||||
|
- '#833a00'
|
||||||
|
- '#ff9ee9'
|
||||||
|
- '#684507'
|
||||||
|
- '#fe4f85'
|
||||||
|
- '#5d0011'
|
||||||
|
- '#ffa67b'
|
||||||
|
- '#88005c'
|
||||||
|
- '#ff9b8f'
|
||||||
|
- '#85000f'
|
||||||
|
- '#ff7581'
|
||||||
|
color_changer: false
|
||||||
|
title_position: out
|
||||||
|
tooltips: true
|
||||||
|
tooltips_use_html: false
|
||||||
|
data_markers: false
|
||||||
|
data_labels: false
|
||||||
|
legend: false
|
||||||
|
legend_position: right
|
||||||
|
background: ''
|
||||||
|
three_dimensional: 0
|
||||||
|
polar: 0
|
||||||
|
dimensions:
|
||||||
|
width: ''
|
||||||
|
width_units: '%'
|
||||||
|
height: ''
|
||||||
|
height_units: ''
|
||||||
|
gauge:
|
||||||
|
max: '100'
|
||||||
|
min: '0'
|
||||||
|
green_from: '85'
|
||||||
|
green_to: '100'
|
||||||
|
yellow_from: '50'
|
||||||
|
yellow_to: '85'
|
||||||
|
red_from: '0'
|
||||||
|
red_to: '50'
|
||||||
|
xaxis:
|
||||||
|
title: ''
|
||||||
|
labels_rotation: '0'
|
||||||
|
yaxis:
|
||||||
|
title: ''
|
||||||
|
min: ''
|
||||||
|
max: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
decimal_count: ''
|
||||||
|
labels_rotation: '0'
|
||||||
|
advanced:
|
||||||
|
debug: false
|
||||||
|
requirements:
|
||||||
|
cdn: true
|
||||||
216
web/modules/charts/config/schema/charts.data_types.schema.yml
Normal file
216
web/modules/charts/config/schema/charts.data_types.schema.yml
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
# Basic data types for charts.
|
||||||
|
|
||||||
|
charts_dimensions:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
width:
|
||||||
|
type: string
|
||||||
|
label: 'Width'
|
||||||
|
width_units:
|
||||||
|
type: string
|
||||||
|
label: 'Width units'
|
||||||
|
height:
|
||||||
|
type: string
|
||||||
|
label: 'Height'
|
||||||
|
height_units:
|
||||||
|
type: string
|
||||||
|
label: 'Height units'
|
||||||
|
|
||||||
|
charts_gauge:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
max:
|
||||||
|
type: string
|
||||||
|
label: 'Gauge maximum value'
|
||||||
|
min:
|
||||||
|
type: string
|
||||||
|
label: 'Gauge minimum value'
|
||||||
|
green_from:
|
||||||
|
type: string
|
||||||
|
label: 'Green minimum value'
|
||||||
|
green_to:
|
||||||
|
type: string
|
||||||
|
label: 'Green maximum value'
|
||||||
|
yellow_from:
|
||||||
|
type: string
|
||||||
|
label: 'Yellow minimum value'
|
||||||
|
yellow_to:
|
||||||
|
type: string
|
||||||
|
label: 'Yellow maximum value'
|
||||||
|
red_from:
|
||||||
|
type: string
|
||||||
|
label: 'Red minimum value'
|
||||||
|
red_to:
|
||||||
|
type: string
|
||||||
|
label: 'Red maximum value'
|
||||||
|
|
||||||
|
charts_display:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
title:
|
||||||
|
type: label
|
||||||
|
label: 'Chart title'
|
||||||
|
title_position:
|
||||||
|
type: string
|
||||||
|
label: 'Title position'
|
||||||
|
subtitle:
|
||||||
|
type: string
|
||||||
|
label: 'Chart subtitle'
|
||||||
|
data_labels:
|
||||||
|
type: boolean
|
||||||
|
label: 'Enable data labels'
|
||||||
|
data_markers:
|
||||||
|
type: boolean
|
||||||
|
label: 'Enable data markers'
|
||||||
|
legend:
|
||||||
|
type: boolean
|
||||||
|
label: 'Legend'
|
||||||
|
legend_position:
|
||||||
|
type: string
|
||||||
|
label: 'Legend position'
|
||||||
|
background:
|
||||||
|
type: string
|
||||||
|
label: 'Background'
|
||||||
|
three_dimensional:
|
||||||
|
type: integer
|
||||||
|
label: 'Make chart three-dimensional (3D)'
|
||||||
|
colors:
|
||||||
|
type: sequence
|
||||||
|
label: 'Chart colors'
|
||||||
|
sequence:
|
||||||
|
type: string
|
||||||
|
label: 'Hexadecimal color'
|
||||||
|
polar:
|
||||||
|
type: integer
|
||||||
|
label: 'Transform cartesian charts into the polar coordinate system'
|
||||||
|
tooltips:
|
||||||
|
type: boolean
|
||||||
|
label: 'Tooltips'
|
||||||
|
tooltips_use_html:
|
||||||
|
type: boolean
|
||||||
|
label: 'Tooltips Use HTML'
|
||||||
|
dimensions:
|
||||||
|
type: charts_dimensions
|
||||||
|
label: 'Dimensions'
|
||||||
|
gauge:
|
||||||
|
type: charts_gauge
|
||||||
|
label: 'Gauge'
|
||||||
|
color_changer:
|
||||||
|
type: boolean
|
||||||
|
label: 'Enable color changer widget'
|
||||||
|
|
||||||
|
charts_xaxis:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
title:
|
||||||
|
type: label
|
||||||
|
label: 'X axis title'
|
||||||
|
labels_rotation:
|
||||||
|
type: string
|
||||||
|
label: 'X axis labels rotation'
|
||||||
|
|
||||||
|
charts_yaxis:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
title:
|
||||||
|
type: label
|
||||||
|
label: 'Y axis title'
|
||||||
|
min:
|
||||||
|
type: string
|
||||||
|
label: 'Y axis min value'
|
||||||
|
max:
|
||||||
|
type: string
|
||||||
|
label: 'Y axis max value'
|
||||||
|
prefix:
|
||||||
|
type: label
|
||||||
|
label: 'Y axis prefix'
|
||||||
|
suffix:
|
||||||
|
type: label
|
||||||
|
label: 'Y axis suffix'
|
||||||
|
decimal_count:
|
||||||
|
type: string
|
||||||
|
label: 'Y axis decimal count'
|
||||||
|
labels_rotation:
|
||||||
|
type: string
|
||||||
|
label: 'Y axis labels rotation'
|
||||||
|
|
||||||
|
charts_views_field_data_provider:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
label: 'Enabled'
|
||||||
|
color:
|
||||||
|
type: string
|
||||||
|
label: Color
|
||||||
|
weight:
|
||||||
|
type: integer
|
||||||
|
label: 'Weight'
|
||||||
|
|
||||||
|
charts_views_field_entity_grouping_selected_method_colors:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
color:
|
||||||
|
type: string
|
||||||
|
label: Color
|
||||||
|
|
||||||
|
charts_config:
|
||||||
|
type: mapping
|
||||||
|
mapping:
|
||||||
|
library:
|
||||||
|
type: string
|
||||||
|
label: 'Charting library'
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
label: 'Chart type'
|
||||||
|
fields:
|
||||||
|
type: mapping
|
||||||
|
label: 'Charts fields'
|
||||||
|
mapping:
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
label: 'Label field'
|
||||||
|
stacking:
|
||||||
|
type: boolean
|
||||||
|
label: Stacking
|
||||||
|
data_providers:
|
||||||
|
type: sequence
|
||||||
|
label: 'Data providers'
|
||||||
|
sequence:
|
||||||
|
type: charts_views_field_data_provider
|
||||||
|
entity_grouping:
|
||||||
|
type: mapping
|
||||||
|
label: 'Entity grouping settings'
|
||||||
|
mapping:
|
||||||
|
color_selection_method:
|
||||||
|
type: string
|
||||||
|
label: 'Color selection method'
|
||||||
|
selected_method:
|
||||||
|
type: mapping
|
||||||
|
label: 'Selected method'
|
||||||
|
mapping:
|
||||||
|
color_field_name:
|
||||||
|
type: string
|
||||||
|
label: 'Color field name'
|
||||||
|
colors:
|
||||||
|
type: sequence
|
||||||
|
label: 'Colors'
|
||||||
|
sequence:
|
||||||
|
type: charts_views_field_entity_grouping_selected_method_colors
|
||||||
|
display:
|
||||||
|
type: charts_display
|
||||||
|
label: 'Display'
|
||||||
|
xaxis:
|
||||||
|
type: charts_yaxis
|
||||||
|
label: 'X axis Display'
|
||||||
|
yaxis:
|
||||||
|
type: charts_yaxis
|
||||||
|
label: 'Y axis Display'
|
||||||
|
library_config:
|
||||||
|
type: charts.settings.library_plugin.[%parent.library]
|
||||||
|
|
||||||
|
charts.settings.library_plugin.*:
|
||||||
|
type: charts_settings_library_plugin
|
||||||
|
|
||||||
|
charts_settings_library_plugin:
|
||||||
|
type: mapping
|
||||||
24
web/modules/charts/config/schema/charts.settings.schema.yml
Executable file
24
web/modules/charts/config/schema/charts.settings.schema.yml
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
charts.settings:
|
||||||
|
type: config_object
|
||||||
|
label: 'Charts settings'
|
||||||
|
mapping:
|
||||||
|
charts_default_settings:
|
||||||
|
type: charts_config
|
||||||
|
label: 'Charts default settings'
|
||||||
|
advanced:
|
||||||
|
type: mapping
|
||||||
|
label: Advanced
|
||||||
|
mapping:
|
||||||
|
debug:
|
||||||
|
type: boolean
|
||||||
|
label: 'Enable Charts Debug'
|
||||||
|
requirements:
|
||||||
|
type: mapping
|
||||||
|
label: Requirements
|
||||||
|
mapping:
|
||||||
|
cdn:
|
||||||
|
type: boolean
|
||||||
|
label: 'Check if CDN is being used for external libraries'
|
||||||
|
dependencies:
|
||||||
|
type: config_dependencies
|
||||||
|
label: 'Dependencies'
|
||||||
47
web/modules/charts/config/schema/charts.views.schema.yml
Executable file
47
web/modules/charts/config/schema/charts.views.schema.yml
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
views.style.chart:
|
||||||
|
type: views_style
|
||||||
|
label: 'Chart'
|
||||||
|
mapping:
|
||||||
|
chart_settings:
|
||||||
|
type: charts_config
|
||||||
|
label: 'Settings'
|
||||||
|
|
||||||
|
views.display.chart_extension:
|
||||||
|
type: views_display
|
||||||
|
label: 'Attachment display options'
|
||||||
|
|
||||||
|
views.field.field_exposed_chart_type:
|
||||||
|
type: views_field
|
||||||
|
label: 'Exposed Chart Type'
|
||||||
|
mapping:
|
||||||
|
chart_types:
|
||||||
|
type: sequence
|
||||||
|
label: 'Chart Type Options'
|
||||||
|
exposed_select_type:
|
||||||
|
type: string
|
||||||
|
label: 'Exposed Selection Type'
|
||||||
|
|
||||||
|
views.field.field_charts_fields_bubble:
|
||||||
|
type: views_field
|
||||||
|
label: 'Bubble Field'
|
||||||
|
mapping:
|
||||||
|
x_axis:
|
||||||
|
type: string
|
||||||
|
label: 'X Axis Field'
|
||||||
|
y_axis:
|
||||||
|
type: string
|
||||||
|
label: 'Y Axis Field'
|
||||||
|
z_axis:
|
||||||
|
type: string
|
||||||
|
label: 'Z Axis Field'
|
||||||
|
|
||||||
|
views.field.field_charts_fields_scatter:
|
||||||
|
type: views_field
|
||||||
|
label: 'Scatter Field'
|
||||||
|
mapping:
|
||||||
|
x_axis:
|
||||||
|
type: string
|
||||||
|
label: 'X Axis Field'
|
||||||
|
y_axis:
|
||||||
|
type: string
|
||||||
|
label: 'Y Axis Field'
|
||||||
46
web/modules/charts/js/charts.es6.js
Normal file
46
web/modules/charts/js/charts.es6.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Charts API.
|
||||||
|
*/
|
||||||
|
((Drupal) => {
|
||||||
|
|
||||||
|
Drupal.Charts = Drupal.Charts || {};
|
||||||
|
Drupal.Charts.Configs = Drupal.Charts.Configs || [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {class} Drupal.Charts.Contents
|
||||||
|
*/
|
||||||
|
|
||||||
|
Drupal.Charts.Contents = class {
|
||||||
|
constructor() {
|
||||||
|
const chartsElements = document.querySelectorAll('[data-chart]');
|
||||||
|
chartsElements.forEach(function (el) {
|
||||||
|
const id = el.getAttribute('id');
|
||||||
|
Drupal.Charts.Configs[id] = JSON.parse(el.getAttribute('data-chart'));
|
||||||
|
Drupal.Charts.Configs[id].drupalChartDivElement = el;
|
||||||
|
Drupal.Charts.Configs[id].drupalChartDivId = id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize(id) {
|
||||||
|
const event = new CustomEvent('drupalChartsConfigsInitialization', {
|
||||||
|
detail: Drupal.Charts.Configs[id]
|
||||||
|
});
|
||||||
|
Drupal.Charts.Configs[id].drupalChartDivElement.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static update(id, data) {
|
||||||
|
if (Drupal.Charts.Configs.hasOwnProperty(id)) {
|
||||||
|
Drupal.Charts.Configs[id] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(id) {
|
||||||
|
if (Drupal.Charts.Configs.hasOwnProperty(id)) {
|
||||||
|
this.initialize(id);
|
||||||
|
return Drupal.Charts.Configs[id];
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(Drupal);
|
||||||
45
web/modules/charts/js/charts.js
Normal file
45
web/modules/charts/js/charts.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT EDIT THIS FILE.
|
||||||
|
* See the following change record for more information,
|
||||||
|
* https://www.drupal.org/node/2815083
|
||||||
|
* @preserve
|
||||||
|
**/
|
||||||
|
|
||||||
|
(Drupal => {
|
||||||
|
Drupal.Charts = Drupal.Charts || {};
|
||||||
|
Drupal.Charts.Configs = Drupal.Charts.Configs || [];
|
||||||
|
Drupal.Charts.Contents = class {
|
||||||
|
constructor() {
|
||||||
|
const charts_elements = document.querySelectorAll('[data-chart]');
|
||||||
|
charts_elements.forEach(function (el) {
|
||||||
|
const id = el.getAttribute('id');
|
||||||
|
Drupal.Charts.Configs[id] = JSON.parse(el.getAttribute('data-chart'));
|
||||||
|
Drupal.Charts.Configs[id].drupalChartDivElement = el;
|
||||||
|
Drupal.Charts.Configs[id].drupalChartDivId = id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize(id) {
|
||||||
|
const event = new CustomEvent('drupalChartsConfigsInitialization', {
|
||||||
|
detail: Drupal.Charts.Configs[id]
|
||||||
|
});
|
||||||
|
Drupal.Charts.Configs[id].drupalChartDivElement.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static update(id, data) {
|
||||||
|
if (Drupal.Charts.Configs.hasOwnProperty(id)) {
|
||||||
|
Drupal.Charts.Configs[id] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(id) {
|
||||||
|
if (Drupal.Charts.Configs.hasOwnProperty(id)) {
|
||||||
|
this.initialize(id);
|
||||||
|
return Drupal.Charts.Configs[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
})(Drupal);
|
||||||
15
web/modules/charts/modules/charts_api_example/README.md
Executable file
15
web/modules/charts/modules/charts_api_example/README.md
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#Charts API Example
|
||||||
|
|
||||||
|
This module shows you how to create charts using render arrays. There are
|
||||||
|
numerous examples in the `ChartsApiExample.php` controller file. In the
|
||||||
|
`charts_api_example.module` file, you can also see how some hooks described in
|
||||||
|
`charts.api.php` can be used. One hook overrides a chart using PHP. Another
|
||||||
|
overrides with JavaScript - this is necessary in some cases when the charting
|
||||||
|
library API is expecting a function rather than a string. You can read more
|
||||||
|
about overriding with JavaScript here:
|
||||||
|
https://www.drupal.org/project/charts/issues/3197574#comment-13999765
|
||||||
|
|
||||||
|
To see the examples in your site, navigate to: `/charts/example/display`
|
||||||
|
|
||||||
|
Settings for these charts are set in the Charts configuration page
|
||||||
|
(`/admin/config/content/charts`).
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
name: 'Charts API Example'
|
||||||
|
type: module
|
||||||
|
description: 'Demonstrates how to use the Charts module without Views.'
|
||||||
|
core_version_requirement: ^10.3 || ^11
|
||||||
|
package: Examples
|
||||||
|
dependencies:
|
||||||
|
- 'charts:charts'
|
||||||
|
|
||||||
|
# Information added by Drupal.org packaging script on 2024-12-02
|
||||||
|
version: '5.1.1'
|
||||||
|
project: 'charts'
|
||||||
|
datestamp: 1733170633
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
charts_api_example:
|
||||||
|
version: VERSION
|
||||||
|
js:
|
||||||
|
js/charts_api_example_js_override.js: { weight: -5 }
|
||||||
|
dependencies:
|
||||||
|
- charts/global
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
charts_api_example.display:
|
||||||
|
title: 'Charts API Example'
|
||||||
|
description: 'Displays charts rendered using the Charts API.'
|
||||||
|
parent: system.admin_config_content
|
||||||
|
route_name: charts_api_example.display
|
||||||
43
web/modules/charts/modules/charts_api_example/charts_api_example.module
Executable file
43
web/modules/charts/modules/charts_api_example/charts_api_example.module
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Charts API Example module file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_help().
|
||||||
|
*/
|
||||||
|
function charts_api_example_help($route_name, RouteMatchInterface $route_match) {
|
||||||
|
$output = '';
|
||||||
|
switch ($route_name) {
|
||||||
|
// Main module help for the charts_api_example module.
|
||||||
|
case 'help.page.charts_api_example':
|
||||||
|
$output .= '<h3>' . t('About') . '</h3>';
|
||||||
|
$output .= '<p>' . t('A simple example on how to interact with the Charts API') . '</p>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_chart_definition_CHART_ID_alter().
|
||||||
|
*/
|
||||||
|
function charts_api_example_chart_definition_exampleidphp_alter(&$chart) {
|
||||||
|
// Please note: this will only show when the charts_highcharts module is
|
||||||
|
// enabled and Highcharts is set as your default library.
|
||||||
|
$chart['chart']['backgroundColor'] = 'blue';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_chart_alter().
|
||||||
|
*/
|
||||||
|
function charts_api_example_chart_alter(array &$element, $chart_id) {
|
||||||
|
// Please note: this will only show when the charts_highcharts module is
|
||||||
|
// enabled and Highcharts is set as your default library.
|
||||||
|
if ($chart_id === 'exampleidjschart') {
|
||||||
|
$element['#attached']['library'][] = 'charts_api_example/charts_api_example';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
charts_api_example.display:
|
||||||
|
path: /charts/example/display
|
||||||
|
defaults:
|
||||||
|
_controller: '\Drupal\charts_api_example\Controller\ChartsApiExample::display'
|
||||||
|
_title: 'How to Use the Charts API'
|
||||||
|
requirements:
|
||||||
|
_permission: 'access content'
|
||||||
16
web/modules/charts/modules/charts_api_example/composer.json
Executable file
16
web/modules/charts/modules/charts_api_example/composer.json
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "drupal/charts_api_example",
|
||||||
|
"type": "drupal-module",
|
||||||
|
"description": "How to interact with the Charts Api",
|
||||||
|
"keywords": [
|
||||||
|
"Drupal"
|
||||||
|
],
|
||||||
|
"license": "GPL-2.0+",
|
||||||
|
"homepage": "https://www.drupal.org/project/charts_api_example",
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://www.drupal.org/project/issues/charts_api_example",
|
||||||
|
"source": "http://cgit.drupalcode.org/charts_api_example"
|
||||||
|
},
|
||||||
|
"require": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,463 @@
|
|||||||
|
Week,6.x-0.x,6.x-1.x,7.x-1.x,7.x-2.x,8.x-1.x,8.x-3.x,8.x-4.x,5.0.x,Total
|
||||||
|
21-Aug-21,0,71,12,13458,1,4632,6,637,18817
|
||||||
|
14-Aug-21,0,77,13,13517,1,4518,9,608,18743
|
||||||
|
7-Aug-21,0,73,11,13586,1,4651,6,606,18934
|
||||||
|
31-Jul-21,0,76,13,13479,1,4488,7,619,18683
|
||||||
|
24-Jul-21,0,70,10,13771,1,4385,7,530,18774
|
||||||
|
17-Jul-21,0,73,12,13756,1,4430,8,536,18816
|
||||||
|
10-Jul-21,0,77,13,13596,1,4362,8,519,18576
|
||||||
|
3-Jul-21,0,75,11,13715,1,4437,8,596,18843
|
||||||
|
26-Jun-21,0,73,12,13925,1,4470,9,651,19141
|
||||||
|
19-Jun-21,0,80,13,13886,1,4583,7,499,19069
|
||||||
|
12-Jun-21,0,79,13,13651,1,4506,9,455,18714
|
||||||
|
5-Jun-21,0,84,12,13656,1,4525,8,457,18743
|
||||||
|
29-May-21,0,79,15,13935,1,4554,10,438,19032
|
||||||
|
22-May-21,0,84,14,13840,1,4511,8,500,18958
|
||||||
|
15-May-21,0,80,13,13790,2,4524,11,553,18973
|
||||||
|
8-May-21,0,85,13,13748,1,4448,9,357,18661
|
||||||
|
1-May-21,0,83,12,13853,0,4371,8,379,18706
|
||||||
|
24-Apr-21,0,82,14,13835,1,4431,6,340,18709
|
||||||
|
17-Apr-21,0,86,14,14080,0,4455,10,322,18967
|
||||||
|
10-Apr-21,0,82,12,13736,0,4326,8,280,18444
|
||||||
|
3-Apr-21,0,82,14,13815,0,4347,8,289,18555
|
||||||
|
27-Mar-21,0,78,12,13490,1,4212,7,325,18125
|
||||||
|
20-Mar-21,0,77,12,13667,0,4389,9,366,18520
|
||||||
|
13-Mar-21,0,77,12,13671,0,4293,9,269,18331
|
||||||
|
6-Mar-21,0,75,14,13840,0,4361,8,253,18551
|
||||||
|
27-Feb-21,0,81,14,14144,1,4413,9,235,18897
|
||||||
|
20-Feb-21,0,83,14,14151,0,4451,10,217,18926
|
||||||
|
13-Feb-21,0,80,13,14057,0,4294,10,247,18701
|
||||||
|
6-Feb-21,0,86,16,14042,0,4271,10,233,18658
|
||||||
|
30-Jan-21,0,78,13,14221,0,4330,7,257,18906
|
||||||
|
23-Jan-21,0,85,13,14109,0,4283,9,192,18691
|
||||||
|
16-Jan-21,0,94,16,14294,0,4227,9,162,18802
|
||||||
|
9-Jan-21,0,88,15,14244,0,4133,9,154,18643
|
||||||
|
2-Jan-21,0,81,14,14235,0,4123,15,145,18613
|
||||||
|
26-Dec-20,0,82,15,13746,0,3721,9,130,17703
|
||||||
|
19-Dec-20,0,83,15,13904,0,3704,9,128,17843
|
||||||
|
12-Dec-20,0,86,16,14299,0,4007,16,170,18594
|
||||||
|
5-Dec-20,0,85,15,14714,0,4047,12,152,19025
|
||||||
|
28-Nov-20,0,81,14,14852,0,3970,16,148,19081
|
||||||
|
21-Nov-20,0,78,16,14817,0,4347,17,108,19383
|
||||||
|
14-Nov-20,0,86,17,14840,0,4567,22,62,19594
|
||||||
|
7-Nov-20,0,87,18,14286,0,4110,18,80,18599
|
||||||
|
31-Oct-20,0,86,19,14599,0,4100,25,49,18878
|
||||||
|
24-Oct-20,0,91,16,14571,0,4157,25,3,18863
|
||||||
|
17-Oct-20,0,84,16,14434,0,5116,25,0,19675
|
||||||
|
10-Oct-20,0,87,15,14563,0,5102,33,0,19800
|
||||||
|
3-Oct-20,0,83,18,14593,0,4059,26,0,18779
|
||||||
|
26-Sep-20,0,88,17,14717,0,3971,23,0,18816
|
||||||
|
19-Sep-20,0,91,20,14605,0,4064,22,0,18802
|
||||||
|
12-Sep-20,0,87,19,14706,0,4865,24,0,19701
|
||||||
|
5-Sep-20,0,88,20,14661,0,4641,29,0,19439
|
||||||
|
29-Aug-20,0,91,19,14814,0,4557,28,0,19509
|
||||||
|
22-Aug-20,0,92,17,14570,0,4572,30,0,19281
|
||||||
|
15-Aug-20,0,84,20,14743,0,4615,32,0,19494
|
||||||
|
8-Aug-20,0,92,20,14800,0,4627,28,0,19567
|
||||||
|
1-Aug-20,0,90,19,14925,0,4433,20,0,19487
|
||||||
|
25-Jul-20,0,92,19,15013,0,4533,19,0,19676
|
||||||
|
18-Jul-20,0,89,20,14750,0,4532,22,0,19413
|
||||||
|
11-Jul-20,0,93,15,14901,0,4594,20,0,19623
|
||||||
|
4-Jul-20,0,88,21,15080,0,4467,26,0,19682
|
||||||
|
27-Jun-20,0,93,19,15281,0,4679,26,0,20098
|
||||||
|
20-Jun-20,0,86,21,15642,0,4835,25,0,20609
|
||||||
|
13-Jun-20,0,91,25,15979,0,4613,23,0,20731
|
||||||
|
6-Jun-20,0,92,23,15597,0,4564,20,0,20296
|
||||||
|
30-May-20,0,86,25,15812,0,4433,17,0,20373
|
||||||
|
23-May-20,0,94,27,15830,0,4163,15,0,20129
|
||||||
|
16-May-20,0,98,29,15739,0,4169,14,0,20049
|
||||||
|
9-May-20,0,98,23,15300,0,4336,12,0,19769
|
||||||
|
2-May-20,0,94,27,15370,0,4261,12,0,19764
|
||||||
|
25-Apr-20,0,99,28,14711,0,4043,9,0,18890
|
||||||
|
18-Apr-20,0,102,25,14857,1,3970,4,0,18959
|
||||||
|
11-Apr-20,0,107,27,14884,0,3966,4,0,18988
|
||||||
|
4-Apr-20,0,104,25,14829,0,3928,3,0,18889
|
||||||
|
28-Mar-20,0,101,25,15302,0,3937,4,0,19369
|
||||||
|
21-Mar-20,0,103,27,15217,1,4067,3,0,19418
|
||||||
|
14-Mar-20,0,107,26,15136,0,3813,1,0,19083
|
||||||
|
7-Mar-20,0,106,26,15202,0,3797,0,0,19131
|
||||||
|
29-Feb-20,0,106,29,15269,1,3795,0,0,19200
|
||||||
|
22-Feb-20,0,106,30,15222,0,3726,0,0,19084
|
||||||
|
15-Feb-20,0,111,29,15289,0,3596,1,0,19026
|
||||||
|
8-Feb-20,0,108,28,15328,0,3667,0,0,19131
|
||||||
|
1-Feb-20,0,110,28,15523,1,3673,0,0,19335
|
||||||
|
25-Jan-20,0,114,25,15279,0,3523,0,0,18941
|
||||||
|
18-Jan-20,0,108,29,15289,0,3549,0,0,18975
|
||||||
|
11-Jan-20,0,115,29,15540,1,3561,0,0,19246
|
||||||
|
4-Jan-20,0,123,26,15612,0,3492,0,0,19253
|
||||||
|
28-Dec-19,0,117,30,15151,0,3065,0,0,18363
|
||||||
|
21-Dec-19,0,122,26,15067,0,3179,0,0,18394
|
||||||
|
14-Dec-19,0,125,27,16078,1,3614,0,0,19845
|
||||||
|
7-Dec-19,0,124,25,16029,0,3634,0,0,19812
|
||||||
|
30-Nov-19,0,127,30,15804,0,3591,1,0,19553
|
||||||
|
23-Nov-19,0,119,28,15640,0,3512,2,0,19301
|
||||||
|
16-Nov-19,0,119,31,15755,1,3659,1,0,19566
|
||||||
|
9-Nov-19,0,129,29,15583,0,3449,3,0,19193
|
||||||
|
2-Nov-19,0,124,32,15773,0,3488,3,0,19420
|
||||||
|
26-Oct-19,0,138,29,15742,0,3345,0,0,19254
|
||||||
|
19-Oct-19,0,129,27,15927,1,3347,0,0,19431
|
||||||
|
12-Oct-19,0,127,31,15761,0,3414,1,0,19334
|
||||||
|
5-Oct-19,0,143,38,15753,0,3405,1,0,19340
|
||||||
|
28-Sep-19,0,139,30,15852,1,3428,1,0,19451
|
||||||
|
21-Sep-19,0,129,29,15753,0,3194,0,0,19105
|
||||||
|
14-Sep-19,0,131,30,15994,0,3107,0,0,19262
|
||||||
|
7-Sep-19,0,134,30,15560,0,3222,0,0,18946
|
||||||
|
31-Aug-19,0,133,35,15642,1,3279,0,0,19090
|
||||||
|
24-Aug-19,0,131,33,15477,0,3163,0,0,18804
|
||||||
|
17-Aug-19,0,145,34,15513,0,3095,0,0,18787
|
||||||
|
10-Aug-19,0,144,29,15331,1,2854,0,0,18359
|
||||||
|
3-Aug-19,0,150,30,15495,0,2924,0,0,18599
|
||||||
|
27-Jul-19,0,135,32,15766,0,2942,0,0,18875
|
||||||
|
20-Jul-19,0,145,35,15715,1,2864,0,0,18760
|
||||||
|
13-Jul-19,0,141,29,15700,0,2975,0,0,18845
|
||||||
|
6-Jul-19,0,140,32,15572,0,3223,0,0,18967
|
||||||
|
29-Jun-19,0,153,32,15719,1,3087,0,0,18992
|
||||||
|
22-Jun-19,0,151,33,15604,1,3045,0,0,18834
|
||||||
|
15-Jun-19,0,147,35,15576,0,3226,0,0,18984
|
||||||
|
8-Jun-19,0,150,29,15515,0,2942,0,0,18636
|
||||||
|
1-Jun-19,0,140,37,15912,0,2724,0,0,18813
|
||||||
|
25-May-19,0,145,32,15847,1,2803,0,0,18828
|
||||||
|
18-May-19,0,142,31,15985,0,3094,0,0,19252
|
||||||
|
11-May-19,0,142,31,16276,2,3083,0,0,19534
|
||||||
|
4-May-19,0,131,30,16204,8,3001,0,0,19374
|
||||||
|
27-Apr-19,0,126,35,15858,7,2788,0,0,18814
|
||||||
|
20-Apr-19,0,134,30,15809,4,2635,0,0,18612
|
||||||
|
13-Apr-19,0,136,32,15934,8,2545,0,0,18655
|
||||||
|
6-Apr-19,0,136,36,15967,7,2652,0,0,18798
|
||||||
|
30-Mar-19,0,135,37,16346,6,2608,0,0,19132
|
||||||
|
23-Mar-19,0,135,32,16429,6,2537,0,0,19139
|
||||||
|
16-Mar-19,0,131,32,16638,4,2370,0,0,19175
|
||||||
|
9-Mar-19,0,138,32,16351,5,2300,0,0,18826
|
||||||
|
2-Mar-19,0,141,34,16383,6,2436,0,0,19000
|
||||||
|
23-Feb-19,0,145,31,16483,7,2458,0,0,19124
|
||||||
|
16-Feb-19,0,143,32,16565,6,2689,0,0,19435
|
||||||
|
9-Feb-19,0,143,37,16169,5,2551,0,0,18905
|
||||||
|
2-Feb-19,0,142,32,16180,4,2437,0,0,18795
|
||||||
|
26-Jan-19,0,136,34,16314,5,2474,0,0,18963
|
||||||
|
19-Jan-19,0,138,30,16504,6,2276,0,0,18954
|
||||||
|
12-Jan-19,0,140,28,16585,7,2294,0,0,19054
|
||||||
|
5-Jan-19,0,140,28,16175,7,2122,0,0,18472
|
||||||
|
29-Dec-18,0,145,31,15571,7,1974,0,0,17728
|
||||||
|
22-Dec-18,0,144,30,15031,4,2009,0,0,17218
|
||||||
|
15-Dec-18,0,145,30,15884,5,2077,0,0,18141
|
||||||
|
8-Dec-18,0,140,35,16095,5,2193,0,0,18468
|
||||||
|
1-Dec-18,0,148,31,16110,3,2268,0,0,18560
|
||||||
|
24-Nov-18,0,145,27,15817,3,2096,0,0,18088
|
||||||
|
17-Nov-18,0,153,25,15964,6,2104,0,0,18252
|
||||||
|
10-Nov-18,0,153,33,15995,7,2074,0,0,18262
|
||||||
|
3-Nov-18,0,158,34,15944,5,2319,0,0,18460
|
||||||
|
27-Oct-18,0,153,34,15920,4,2400,0,0,18511
|
||||||
|
20-Oct-18,0,150,31,16208,5,2237,0,0,18631
|
||||||
|
13-Oct-18,0,153,30,16470,4,2200,0,0,18857
|
||||||
|
6-Oct-18,0,153,32,15848,4,1926,0,0,17963
|
||||||
|
29-Sep-18,0,155,36,15769,5,1929,0,0,17894
|
||||||
|
22-Sep-18,0,157,29,15572,4,1852,0,0,17614
|
||||||
|
15-Sep-18,0,158,29,15334,5,1998,0,0,17524
|
||||||
|
8-Sep-18,0,161,28,15815,4,1974,0,0,17982
|
||||||
|
1-Sep-18,0,162,30,15825,4,2001,0,0,18022
|
||||||
|
25-Aug-18,0,156,29,15769,4,1929,0,0,17887
|
||||||
|
18-Aug-18,0,152,29,15565,4,1775,0,0,17525
|
||||||
|
11-Aug-18,0,150,30,15460,4,1860,0,0,17504
|
||||||
|
4-Aug-18,0,157,36,15504,5,1979,0,0,17681
|
||||||
|
28-Jul-18,0,157,32,15243,2,1898,0,0,17332
|
||||||
|
21-Jul-18,0,161,31,15322,0,1850,0,0,17364
|
||||||
|
14-Jul-18,0,138,34,14741,0,1725,0,0,16638
|
||||||
|
7-Jul-18,0,158,35,15621,0,1700,0,0,17514
|
||||||
|
30-Jun-18,0,145,31,13791,0,1442,0,0,15409
|
||||||
|
23-Jun-18,0,165,36,15441,0,1594,0,0,17236
|
||||||
|
16-Jun-18,0,162,35,15550,0,1633,0,0,17380
|
||||||
|
9-Jun-18,0,157,39,15502,0,1650,0,0,17348
|
||||||
|
2-Jun-18,0,167,34,15757,3,1795,0,0,17756
|
||||||
|
26-May-18,0,176,33,15551,0,1487,0,0,17247
|
||||||
|
19-May-18,0,173,37,15841,0,1554,0,0,17605
|
||||||
|
12-May-18,0,168,30,16140,0,1400,0,0,17738
|
||||||
|
5-May-18,0,174,34,16049,0,1460,0,0,17717
|
||||||
|
28-Apr-18,0,216,35,16600,0,1485,0,0,18336
|
||||||
|
21-Apr-18,0,181,33,18067,0,1517,0,0,19798
|
||||||
|
14-Apr-18,0,181,32,16873,2,1712,0,0,18800
|
||||||
|
7-Apr-18,0,177,38,16800,4,1558,0,0,18577
|
||||||
|
31-Mar-18,0,184,32,16736,2,1457,0,0,18411
|
||||||
|
24-Mar-18,0,195,31,17965,3,1458,0,0,19652
|
||||||
|
17-Mar-18,0,184,35,16418,2,1380,0,0,18019
|
||||||
|
10-Mar-18,0,184,32,16795,2,1419,0,0,18432
|
||||||
|
3-Mar-18,0,193,35,16780,2,1520,0,0,18530
|
||||||
|
24-Feb-18,0,190,31,16427,2,1338,0,0,17988
|
||||||
|
17-Feb-18,0,204,34,16367,2,1274,0,0,17881
|
||||||
|
10-Feb-18,0,196,36,16275,1,1292,0,0,17800
|
||||||
|
3-Feb-18,0,206,34,16345,3,1527,0,0,18115
|
||||||
|
27-Jan-18,0,196,33,16268,5,1385,0,0,17887
|
||||||
|
20-Jan-18,0,202,36,15935,2,1450,0,0,17625
|
||||||
|
13-Jan-18,0,200,33,15856,7,1320,0,0,17416
|
||||||
|
6-Jan-18,0,209,38,16034,3,1285,0,0,17569
|
||||||
|
30-Dec-17,0,204,39,15544,2,1056,0,0,16845
|
||||||
|
23-Dec-17,0,206,35,15002,2,1039,0,0,16284
|
||||||
|
16-Dec-17,0,203,35,15809,3,1123,0,0,17173
|
||||||
|
9-Dec-17,0,206,32,15921,2,1477,0,0,17638
|
||||||
|
2-Dec-17,0,204,38,16419,2,1339,0,0,18002
|
||||||
|
25-Nov-17,0,210,33,16087,2,1193,0,0,17525
|
||||||
|
18-Nov-17,0,205,39,16106,3,1096,0,0,17449
|
||||||
|
11-Nov-17,0,210,39,16304,2,1081,0,0,17636
|
||||||
|
4-Nov-17,0,227,40,16241,3,1163,0,0,17674
|
||||||
|
28-Oct-17,0,217,39,15860,4,909,0,0,17029
|
||||||
|
21-Oct-17,0,226,39,15948,4,863,0,0,17080
|
||||||
|
14-Oct-17,0,227,43,16086,3,922,0,0,17281
|
||||||
|
7-Oct-17,0,235,45,16215,2,932,0,0,17429
|
||||||
|
30-Sep-17,0,237,38,16037,2,800,0,0,17114
|
||||||
|
23-Sep-17,0,243,42,15838,4,715,0,0,16842
|
||||||
|
16-Sep-17,0,239,39,15716,4,962,0,0,16960
|
||||||
|
9-Sep-17,0,242,44,15784,2,659,0,0,16731
|
||||||
|
2-Sep-17,0,254,46,15812,2,760,0,0,16874
|
||||||
|
26-Aug-17,0,254,43,15805,2,681,0,0,16785
|
||||||
|
19-Aug-17,0,265,45,15748,3,533,0,0,16594
|
||||||
|
12-Aug-17,0,242,38,14836,2,474,0,0,15592
|
||||||
|
5-Aug-17,0,264,39,15242,3,572,0,0,16120
|
||||||
|
29-Jul-17,0,263,41,15266,1,288,0,0,15859
|
||||||
|
22-Jul-17,0,259,44,15357,2,134,0,0,15796
|
||||||
|
15-Jul-17,0,269,38,15512,2,132,0,0,15953
|
||||||
|
8-Jul-17,0,261,47,15717,3,124,0,0,16152
|
||||||
|
1-Jul-17,0,262,43,15617,3,114,0,0,16039
|
||||||
|
24-Jun-17,0,261,44,15799,3,113,0,0,16220
|
||||||
|
17-Jun-17,0,270,42,15745,3,107,0,0,16167
|
||||||
|
10-Jun-17,0,279,42,15587,4,112,0,0,16024
|
||||||
|
3-Jun-17,0,278,49,15721,4,105,0,0,16157
|
||||||
|
27-May-17,0,289,50,15553,4,100,0,0,15996
|
||||||
|
20-May-17,0,286,45,15504,2,92,0,0,15929
|
||||||
|
13-May-17,0,290,46,16796,2,93,0,0,17227
|
||||||
|
6-May-17,0,286,45,17445,4,74,0,0,17854
|
||||||
|
29-Apr-17,0,297,46,17294,3,62,0,0,17702
|
||||||
|
22-Apr-17,0,296,46,17500,3,63,0,0,17908
|
||||||
|
15-Apr-17,0,290,48,17485,3,47,0,0,17873
|
||||||
|
8-Apr-17,0,293,46,17367,3,36,0,0,17745
|
||||||
|
1-Apr-17,0,298,43,17508,7,31,0,0,17887
|
||||||
|
25-Mar-17,0,300,47,17271,10,27,0,0,17655
|
||||||
|
18-Mar-17,0,304,47,17267,14,10,0,0,17642
|
||||||
|
11-Mar-17,0,296,43,16712,19,0,0,0,17070
|
||||||
|
4-Mar-17,0,303,46,16999,3,0,0,0,17351
|
||||||
|
25-Feb-17,0,307,48,16959,0,0,0,0,17314
|
||||||
|
18-Feb-17,0,320,45,16806,0,0,0,0,17171
|
||||||
|
11-Feb-17,0,305,40,16866,0,0,0,0,17211
|
||||||
|
4-Feb-17,0,294,42,16988,0,0,0,0,17324
|
||||||
|
28-Jan-17,0,312,43,16604,0,0,0,0,16959
|
||||||
|
21-Jan-17,0,291,48,16706,0,0,0,0,17045
|
||||||
|
14-Jan-17,0,310,46,16459,0,0,0,0,16815
|
||||||
|
7-Jan-17,0,318,51,16878,0,0,0,0,17247
|
||||||
|
31-Dec-16,0,318,45,15947,0,0,0,0,16310
|
||||||
|
24-Dec-16,0,311,45,15031,0,0,0,0,15387
|
||||||
|
17-Dec-16,0,319,46,16005,0,0,0,0,16370
|
||||||
|
10-Dec-16,0,318,42,16210,0,0,0,0,16570
|
||||||
|
3-Dec-16,0,332,52,16549,0,0,0,0,16933
|
||||||
|
26-Nov-16,0,334,46,16549,0,0,0,0,16929
|
||||||
|
19-Nov-16,0,332,51,15957,0,0,0,0,16340
|
||||||
|
12-Nov-16,0,342,49,16191,0,0,0,0,16582
|
||||||
|
5-Nov-16,0,345,56,15339,0,0,0,0,15740
|
||||||
|
29-Oct-16,0,349,49,14911,0,0,0,0,15309
|
||||||
|
22-Oct-16,0,350,53,15040,0,0,0,0,15443
|
||||||
|
15-Oct-16,0,348,53,15238,0,0,0,0,15639
|
||||||
|
8-Oct-16,0,350,52,14567,0,0,0,0,14969
|
||||||
|
1-Oct-16,0,352,63,15041,0,0,0,0,15456
|
||||||
|
24-Sep-16,0,351,60,14551,0,0,0,0,14962
|
||||||
|
17-Sep-16,0,347,58,14655,0,0,0,0,15060
|
||||||
|
10-Sep-16,0,338,62,14584,0,0,0,0,14984
|
||||||
|
3-Sep-16,0,355,62,14582,0,0,0,0,14999
|
||||||
|
27-Aug-16,0,352,67,14673,0,0,0,0,15092
|
||||||
|
20-Aug-16,0,359,63,14400,0,0,0,0,14822
|
||||||
|
13-Aug-16,0,392,61,14415,0,0,0,0,14868
|
||||||
|
6-Aug-16,0,373,62,14653,0,0,0,0,15088
|
||||||
|
30-Jul-16,0,367,60,14607,0,0,0,0,15034
|
||||||
|
23-Jul-16,0,374,58,14741,0,0,0,0,15173
|
||||||
|
16-Jul-16,0,415,57,14959,0,0,0,0,15431
|
||||||
|
9-Jul-16,0,439,58,13846,0,0,0,0,14343
|
||||||
|
2-Jul-16,0,378,59,14610,0,0,0,0,15047
|
||||||
|
25-Jun-16,0,392,62,14607,0,0,0,0,15061
|
||||||
|
18-Jun-16,0,380,65,14953,0,0,0,0,15398
|
||||||
|
11-Jun-16,0,398,58,14869,0,0,0,0,15325
|
||||||
|
4-Jun-16,0,379,63,14444,0,0,0,0,14886
|
||||||
|
28-May-16,0,406,68,14443,0,0,0,0,14917
|
||||||
|
21-May-16,0,396,68,14739,0,0,0,0,15203
|
||||||
|
14-May-16,0,391,58,14553,0,0,0,0,15002
|
||||||
|
7-May-16,0,393,72,14577,0,0,0,0,15042
|
||||||
|
30-Apr-16,0,391,67,14347,0,0,0,0,14805
|
||||||
|
23-Apr-16,0,412,65,14447,0,0,0,0,14924
|
||||||
|
16-Apr-16,0,392,65,14611,0,0,0,0,15068
|
||||||
|
9-Apr-16,0,414,68,14426,0,0,0,0,14908
|
||||||
|
2-Apr-16,0,410,67,14537,0,0,0,0,15014
|
||||||
|
26-Mar-16,0,407,74,14040,0,0,0,0,14521
|
||||||
|
19-Mar-16,0,418,73,13893,0,0,0,0,14384
|
||||||
|
12-Mar-16,0,419,76,14256,0,0,0,0,14751
|
||||||
|
5-Mar-16,0,440,73,14272,0,0,0,0,14785
|
||||||
|
27-Feb-16,0,437,78,14293,0,0,0,0,14808
|
||||||
|
20-Feb-16,0,448,78,14500,0,0,0,0,15026
|
||||||
|
13-Feb-16,0,458,74,13949,0,0,0,0,14481
|
||||||
|
6-Feb-16,0,437,76,13681,0,0,0,0,14194
|
||||||
|
30-Jan-16,0,428,76,13729,0,0,0,0,14233
|
||||||
|
23-Jan-16,0,435,80,13393,0,0,0,0,13908
|
||||||
|
16-Jan-16,0,441,79,13369,0,0,0,0,13889
|
||||||
|
9-Jan-16,0,443,77,13298,0,0,0,0,13818
|
||||||
|
2-Jan-16,0,450,77,12385,0,0,0,0,12912
|
||||||
|
26-Dec-15,0,446,84,11190,0,0,0,0,11720
|
||||||
|
19-Dec-15,0,452,92,11888,0,0,0,0,12432
|
||||||
|
12-Dec-15,0,468,84,12623,0,0,0,0,13175
|
||||||
|
5-Dec-15,0,465,87,12736,0,0,0,0,13288
|
||||||
|
28-Nov-15,0,460,86,12721,0,0,0,0,13267
|
||||||
|
21-Nov-15,0,465,88,12423,0,0,0,0,12976
|
||||||
|
14-Nov-15,0,494,90,12483,0,0,0,0,13067
|
||||||
|
7-Nov-15,0,489,89,12383,0,0,0,0,12961
|
||||||
|
31-Oct-15,0,509,87,12512,0,0,0,0,13108
|
||||||
|
24-Oct-15,0,495,88,12346,0,0,0,0,12929
|
||||||
|
17-Oct-15,0,505,90,12338,0,0,0,0,12933
|
||||||
|
10-Oct-15,0,487,96,11995,0,0,0,0,12578
|
||||||
|
3-Oct-15,0,489,87,11676,0,0,0,0,12252
|
||||||
|
26-Sep-15,0,480,93,11015,0,0,0,0,11588
|
||||||
|
19-Sep-15,0,474,85,10385,0,0,0,0,10944
|
||||||
|
12-Sep-15,0,506,94,11041,0,0,0,0,11641
|
||||||
|
5-Sep-15,0,519,101,11402,0,0,0,0,12022
|
||||||
|
29-Aug-15,0,528,106,11556,0,0,0,0,12190
|
||||||
|
22-Aug-15,0,596,106,11672,0,0,0,0,12374
|
||||||
|
15-Aug-15,0,530,105,11574,0,0,0,0,12209
|
||||||
|
8-Aug-15,1,520,103,11089,0,0,0,0,11713
|
||||||
|
1-Aug-15,1,507,106,10947,0,0,0,0,11561
|
||||||
|
25-Jul-15,1,593,107,10712,0,0,0,0,11413
|
||||||
|
18-Jul-15,1,520,104,10533,0,0,0,0,11158
|
||||||
|
11-Jul-15,1,538,110,10764,0,0,0,0,11413
|
||||||
|
4-Jul-15,1,550,108,10918,0,0,0,0,11577
|
||||||
|
27-Jun-15,1,537,114,10783,0,0,0,0,11435
|
||||||
|
20-Jun-15,1,564,109,10961,0,0,0,0,11635
|
||||||
|
13-Jun-15,1,550,114,10845,0,0,0,0,11510
|
||||||
|
6-Jun-15,1,540,112,10369,0,0,0,0,11022
|
||||||
|
30-May-15,1,537,115,10137,0,0,0,0,10790
|
||||||
|
23-May-15,1,532,116,10024,0,0,0,0,10673
|
||||||
|
16-May-15,1,556,115,10051,0,0,0,0,10723
|
||||||
|
9-May-15,1,549,112,9923,0,0,0,0,10585
|
||||||
|
2-May-15,1,549,115,9700,0,0,0,0,10365
|
||||||
|
25-Apr-15,1,555,118,9462,0,0,0,0,10136
|
||||||
|
18-Apr-15,1,552,121,9363,0,0,0,0,10037
|
||||||
|
11-Apr-15,1,549,122,9046,0,0,0,0,9718
|
||||||
|
4-Apr-15,1,561,130,8955,0,0,0,0,9647
|
||||||
|
28-Mar-15,1,570,125,9064,0,0,0,0,9760
|
||||||
|
21-Mar-15,1,568,134,9194,0,0,0,0,9897
|
||||||
|
14-Mar-15,1,561,137,9163,0,0,0,0,9862
|
||||||
|
7-Mar-15,1,553,127,8826,0,0,0,0,9507
|
||||||
|
28-Feb-15,1,587,130,8638,0,0,0,0,9356
|
||||||
|
21-Feb-15,1,584,124,8459,0,0,0,0,9168
|
||||||
|
14-Feb-15,1,588,136,8314,0,0,0,0,9039
|
||||||
|
7-Feb-15,1,577,142,8240,0,0,0,0,8960
|
||||||
|
31-Jan-15,1,583,133,8003,0,0,0,0,8720
|
||||||
|
24-Jan-15,1,598,130,7738,0,0,0,0,8467
|
||||||
|
17-Jan-15,1,593,138,7779,0,0,0,0,8511
|
||||||
|
10-Jan-15,1,579,137,7654,0,0,0,0,8371
|
||||||
|
3-Jan-15,1,581,127,7500,0,0,0,0,8209
|
||||||
|
27-Dec-14,1,562,131,6455,0,0,0,0,7149
|
||||||
|
20-Dec-14,1,582,129,6575,0,0,0,0,7287
|
||||||
|
13-Dec-14,1,602,134,7342,0,0,0,0,8079
|
||||||
|
6-Dec-14,1,602,139,7319,0,0,0,0,8061
|
||||||
|
29-Nov-14,1,609,134,7171,0,0,0,0,7915
|
||||||
|
22-Nov-14,1,630,144,7088,0,0,0,0,7863
|
||||||
|
15-Nov-14,1,625,160,7301,0,0,0,0,8087
|
||||||
|
8-Nov-14,1,617,151,7029,0,0,0,0,7798
|
||||||
|
1-Nov-14,2,635,166,6769,0,0,0,0,7572
|
||||||
|
25-Oct-14,1,614,160,6508,0,0,0,0,7283
|
||||||
|
18-Oct-14,1,609,159,6348,0,0,0,0,7117
|
||||||
|
11-Oct-14,1,627,155,6349,0,0,0,0,7132
|
||||||
|
4-Oct-14,1,621,165,5897,0,0,0,0,6684
|
||||||
|
27-Sep-14,1,622,158,5854,0,0,0,0,6635
|
||||||
|
20-Sep-14,1,633,164,5881,0,0,0,0,6679
|
||||||
|
13-Sep-14,1,654,161,5789,0,0,0,0,6605
|
||||||
|
6-Sep-14,1,652,166,5700,0,0,0,0,6519
|
||||||
|
30-Aug-14,2,643,171,5580,0,0,0,0,6396
|
||||||
|
23-Aug-14,2,643,171,5466,0,0,0,0,6282
|
||||||
|
16-Aug-14,2,633,184,5304,0,0,0,0,6123
|
||||||
|
9-Aug-14,2,648,185,5183,0,0,0,0,6018
|
||||||
|
2-Aug-14,2,641,183,5247,0,0,0,0,6073
|
||||||
|
26-Jul-14,2,643,185,4938,0,0,0,0,5768
|
||||||
|
19-Jul-14,2,640,183,4814,0,0,0,0,5639
|
||||||
|
12-Jul-14,2,719,175,4713,0,0,0,0,5609
|
||||||
|
5-Jul-14,2,652,177,4543,0,0,0,0,5374
|
||||||
|
28-Jun-14,2,653,182,4526,0,0,0,0,5363
|
||||||
|
21-Jun-14,2,655,181,4490,0,0,0,0,5328
|
||||||
|
14-Jun-14,2,651,166,3895,0,0,0,0,4714
|
||||||
|
7-Jun-14,2,674,187,3866,0,0,0,0,4729
|
||||||
|
31-May-14,2,665,183,3623,0,0,0,0,4473
|
||||||
|
24-May-14,2,669,194,3581,0,0,0,0,4446
|
||||||
|
17-May-14,2,669,191,3346,0,0,0,0,4208
|
||||||
|
10-May-14,2,671,196,3221,0,0,0,0,4090
|
||||||
|
3-May-14,2,661,192,3223,0,0,0,0,4078
|
||||||
|
26-Apr-14,2,681,194,3095,0,0,0,0,3972
|
||||||
|
19-Apr-14,2,687,201,2981,0,0,0,0,3871
|
||||||
|
12-Apr-14,2,695,203,2910,0,0,0,0,3810
|
||||||
|
5-Apr-14,2,694,218,2807,0,0,0,0,3721
|
||||||
|
29-Mar-14,2,725,222,2807,0,0,0,0,3756
|
||||||
|
22-Mar-14,2,709,226,2661,0,0,0,0,3598
|
||||||
|
15-Mar-14,2,712,235,2544,0,0,0,0,3493
|
||||||
|
8-Mar-14,2,747,241,2405,0,0,0,0,3395
|
||||||
|
1-Mar-14,2,715,255,2368,0,0,0,0,3340
|
||||||
|
22-Feb-14,2,748,244,2245,0,0,0,0,3239
|
||||||
|
15-Feb-14,2,707,248,2107,0,0,0,0,3064
|
||||||
|
8-Feb-14,2,759,256,2044,0,0,0,0,3061
|
||||||
|
1-Feb-14,2,734,258,1928,0,0,0,0,2922
|
||||||
|
25-Jan-14,2,753,263,1781,0,0,0,0,2799
|
||||||
|
18-Jan-14,2,749,260,1722,0,0,0,0,2733
|
||||||
|
11-Jan-14,2,728,288,1612,0,0,0,0,2630
|
||||||
|
4-Jan-14,2,755,276,1343,0,0,0,0,2376
|
||||||
|
28-Dec-13,2,736,285,1082,0,0,0,0,2105
|
||||||
|
21-Dec-13,2,711,276,1005,0,0,0,0,1994
|
||||||
|
14-Dec-13,2,769,285,1118,0,0,0,0,2174
|
||||||
|
7-Dec-13,2,756,281,1008,0,0,0,0,2047
|
||||||
|
30-Nov-13,2,799,286,920,0,0,0,0,2007
|
||||||
|
23-Nov-13,2,898,290,849,0,0,0,0,2039
|
||||||
|
16-Nov-13,2,956,313,790,0,0,0,0,2061
|
||||||
|
9-Nov-13,2,939,313,746,0,0,0,0,2000
|
||||||
|
2-Nov-13,2,963,327,662,0,0,0,0,1954
|
||||||
|
26-Oct-13,2,992,322,636,0,0,0,0,1952
|
||||||
|
19-Oct-13,2,977,309,651,0,0,0,0,1939
|
||||||
|
12-Oct-13,2,990,328,576,0,0,0,0,1896
|
||||||
|
5-Oct-13,2,887,328,560,0,0,0,0,1777
|
||||||
|
28-Sep-13,2,1450,331,516,0,0,0,0,2299
|
||||||
|
21-Sep-13,2,1510,336,449,0,0,0,0,2297
|
||||||
|
14-Sep-13,2,1530,335,423,0,0,0,0,2290
|
||||||
|
7-Sep-13,2,874,340,363,0,0,0,0,1579
|
||||||
|
31-Aug-13,2,887,353,317,0,0,0,0,1559
|
||||||
|
24-Aug-13,2,870,349,269,0,0,0,0,1490
|
||||||
|
17-Aug-13,2,877,352,235,0,0,0,0,1466
|
||||||
|
10-Aug-13,2,862,367,190,0,0,0,0,1421
|
||||||
|
3-Aug-13,2,841,399,149,0,0,0,0,1391
|
||||||
|
27-Jul-13,2,876,416,104,0,0,0,0,1398
|
||||||
|
20-Jul-13,2,887,457,15,0,0,0,0,1361
|
||||||
|
13-Jul-13,2,879,445,0,0,0,0,0,1326
|
||||||
|
6-Jul-13,2,876,462,0,0,0,0,0,1340
|
||||||
|
29-Jun-13,2,884,464,0,0,0,0,0,1350
|
||||||
|
22-Jun-13,2,901,452,0,0,0,0,0,1355
|
||||||
|
15-Jun-13,2,893,460,0,0,0,0,0,1355
|
||||||
|
8-Jun-13,2,956,474,0,0,0,0,0,1432
|
||||||
|
1-Jun-13,2,1117,473,0,0,0,0,0,1592
|
||||||
|
25-May-13,2,1063,441,0,0,0,0,0,1506
|
||||||
|
18-May-13,2,944,383,0,0,0,0,0,1329
|
||||||
|
11-May-13,2,1109,450,0,0,0,0,0,1561
|
||||||
|
4-May-13,2,1020,451,0,0,0,0,0,1473
|
||||||
|
27-Apr-13,2,1003,450,0,0,0,0,0,1455
|
||||||
|
20-Apr-13,2,967,448,0,0,0,0,0,1417
|
||||||
|
13-Apr-13,2,1061,469,0,0,0,0,0,1532
|
||||||
|
6-Apr-13,2,1022,478,0,0,0,0,0,1502
|
||||||
|
30-Mar-13,2,1030,440,0,0,0,0,0,1472
|
||||||
|
23-Mar-13,2,1101,464,0,0,0,0,0,1567
|
||||||
|
16-Mar-13,2,1047,451,0,0,0,0,0,1500
|
||||||
|
9-Mar-13,2,1046,476,0,0,0,0,0,1524
|
||||||
|
2-Mar-13,3,1044,469,0,0,0,0,0,1516
|
||||||
|
23-Feb-13,3,1077,479,0,0,0,0,0,1559
|
||||||
|
16-Feb-13,3,1094,458,0,0,0,0,0,1555
|
||||||
|
9-Feb-13,3,1091,468,0,0,0,0,0,1562
|
||||||
|
2-Feb-13,3,1099,447,0,0,0,0,0,1549
|
||||||
|
26-Jan-13,3,1132,452,0,0,0,0,0,1587
|
||||||
|
19-Jan-13,3,1124,455,0,0,0,0,0,1582
|
||||||
|
12-Jan-13,4,1164,446,0,0,0,0,0,1614
|
||||||
|
5-Jan-13,3,1167,443,0,0,0,0,0,1613
|
||||||
|
29-Dec-12,3,1085,411,0,0,0,0,0,1499
|
||||||
|
22-Dec-12,3,1076,407,0,0,0,0,0,1486
|
||||||
|
15-Dec-12,4,1173,437,0,0,0,0,0,1614
|
||||||
|
8-Dec-12,4,1208,441,0,0,0,0,0,1653
|
||||||
|
1-Dec-12,3,1171,476,0,0,0,0,0,1650
|
||||||
|
24-Nov-12,3,1185,474,0,0,0,0,0,1662
|
||||||
|
17-Nov-12,3,1163,460,0,0,0,0,0,1626
|
||||||
|
10-Nov-12,3,1200,451,0,0,0,0,0,1654
|
||||||
|
3-Nov-12,3,1247,476,0,0,0,0,0,1726
|
||||||
|
27-Oct-12,3,1219,456,0,0,0,0,0,1678
|
||||||
|
20-Oct-12,3,1276,443,0,0,0,0,0,1722
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
Drupal.charts_api_example = Drupal.charts_api_example || {};
|
||||||
|
// PLEASE NOTE: this example is structured to work for Highcharts, but you
|
||||||
|
// do the same thing for any of the charting libraries.
|
||||||
|
Drupal.charts_api_example.highchartsTooltipFormatter = function () {
|
||||||
|
return 'The value for <b>' + this.x +
|
||||||
|
'</b> is <b>' + this.y + '</b>';
|
||||||
|
};
|
||||||
|
Drupal.behaviors.chartsApiExampleCharts = {
|
||||||
|
attach: function (context, settings) {
|
||||||
|
let chartcontainer = document.getElementById('exampleidjs');
|
||||||
|
chartcontainer.addEventListener('drupalChartsConfigsInitialization', function (e) {
|
||||||
|
let data = e.detail;
|
||||||
|
const id = data.drupalChartDivId;
|
||||||
|
// Change the background of the chart to green.
|
||||||
|
data.chart.backgroundColor = 'green';
|
||||||
|
// Replace the tooltip formatter.
|
||||||
|
data.tooltip.formatter = Drupal.charts_api_example.highchartsTooltipFormatter;
|
||||||
|
Drupal.Charts.Contents.update(id, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}());
|
||||||
@@ -0,0 +1,400 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\charts_api_example\Controller;
|
||||||
|
|
||||||
|
use Drupal\Component\Uuid\UuidInterface;
|
||||||
|
use Drupal\Core\Controller\ControllerBase;
|
||||||
|
use Drupal\Core\Extension\ModuleExtensionList;
|
||||||
|
use Drupal\Core\Messenger\MessengerInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charts Api Example.
|
||||||
|
*/
|
||||||
|
class ChartsApiExample extends ControllerBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The messenger service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Messenger\MessengerInterface
|
||||||
|
*/
|
||||||
|
protected $messenger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UUID service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Component\Uuid\UuidInterface
|
||||||
|
*/
|
||||||
|
protected $uuidService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module extension list.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Extension\ModuleExtensionList
|
||||||
|
*/
|
||||||
|
protected $moduleList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct.
|
||||||
|
*
|
||||||
|
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
|
||||||
|
* The messenger service.
|
||||||
|
* @param \Drupal\Component\Uuid\UuidInterface $uuidService
|
||||||
|
* The UUID service.
|
||||||
|
* @param \Drupal\Core\Extension\ModuleExtensionList $module_list
|
||||||
|
* The module list.
|
||||||
|
*/
|
||||||
|
public function __construct(MessengerInterface $messenger, UuidInterface $uuidService, ModuleExtensionList $module_list) {
|
||||||
|
$this->messenger = $messenger;
|
||||||
|
$this->uuidService = $uuidService;
|
||||||
|
$this->moduleList = $module_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container) {
|
||||||
|
return new static(
|
||||||
|
$container->get('messenger'),
|
||||||
|
$container->get('uuid'),
|
||||||
|
$container->get('extension.list.module')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the dashboard of charts.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Array to render.
|
||||||
|
*/
|
||||||
|
public function display() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you do not set a library specifically in your render array, Charts
|
||||||
|
* will use your default. But you do need to set your default library.
|
||||||
|
*/
|
||||||
|
$charts_settings = $this->config('charts.settings');
|
||||||
|
$library = $charts_settings->get('charts_default_settings.library');
|
||||||
|
if (empty($library)) {
|
||||||
|
$this->messenger->addError($this->t('You need to first configure Charts default settings'));
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a container for all the charts below.
|
||||||
|
$charts_container = [
|
||||||
|
'#type' => 'container',
|
||||||
|
'content' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
/* Listing all the default chart types except 'gauge' and 'scatter'
|
||||||
|
* (they come later).
|
||||||
|
*/
|
||||||
|
$chart_types = ['area', 'bar', 'column', 'line', 'spline', 'pie', 'donut'];
|
||||||
|
|
||||||
|
// Define a series to be used in multiple examples.
|
||||||
|
$series = [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('5.0.x'),
|
||||||
|
'#data' => [257, 235, 325, 340],
|
||||||
|
'#color' => '#1d84c3',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Define an x-axis to be used in multiple examples.
|
||||||
|
$xaxis = [
|
||||||
|
'#type' => 'chart_xaxis',
|
||||||
|
'#title' => $this->t('Months'),
|
||||||
|
'#labels' => [
|
||||||
|
$this->t('January 2021'),
|
||||||
|
$this->t('February 2021'),
|
||||||
|
$this->t('March 2021'),
|
||||||
|
$this->t('April 2021'),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Define a y-axis to be used in multiple examples.
|
||||||
|
$yaxis = [
|
||||||
|
'#type' => 'chart_yaxis',
|
||||||
|
'#title' => $this->t('Number of Installs'),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Iterate through the chart types and build a chart for each.
|
||||||
|
foreach ($chart_types as $type) {
|
||||||
|
$charts_container['content'][$type] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library @type Chart', [
|
||||||
|
'@library' => ucfirst($library),
|
||||||
|
'@type' => ucfirst($type),
|
||||||
|
]),
|
||||||
|
'#chart_type' => $type,
|
||||||
|
'series' => $series,
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#raw_options' => [],
|
||||||
|
// e.g. ['chart' => ['backgroundColor' => '#000000']].
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column chart with two series.
|
||||||
|
$charts_container['content']['two_series_column'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Column Chart (Two Series)', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'column',
|
||||||
|
'series_one' => $series,
|
||||||
|
'series_two' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('8.x-3.x'),
|
||||||
|
'#data' => [4330, 4413, 4212, 4431],
|
||||||
|
'#color' => '#77b259',
|
||||||
|
],
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Stacked Area Chart from a local CSV file.
|
||||||
|
$file_contents = $this->getCsvContents();
|
||||||
|
$charts_container['content']['from_csv_file'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Stacked Area Chart from CSV File', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'area',
|
||||||
|
'series_seven_2' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('7.x-2.x'),
|
||||||
|
// Using array_reverse because my file is desc rather than asc.
|
||||||
|
'#data' => array_reverse($file_contents['7.x-2.x']),
|
||||||
|
'#color' => '#76b7b2',
|
||||||
|
],
|
||||||
|
'series_eight_three' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('8.x-3.x'),
|
||||||
|
'#data' => array_reverse($file_contents['8.x-3.x']),
|
||||||
|
'#color' => '#edc949',
|
||||||
|
],
|
||||||
|
'series_five_zero' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('5.0.x'),
|
||||||
|
'#data' => array_reverse($file_contents['5.0.x']),
|
||||||
|
'#color' => '#ff9da7',
|
||||||
|
],
|
||||||
|
'x_axis' => [
|
||||||
|
'#type' => 'chart_xaxis',
|
||||||
|
'#title' => $this->t('Week'),
|
||||||
|
'#labels' => array_reverse($file_contents['Week']),
|
||||||
|
],
|
||||||
|
'y_axis' => [
|
||||||
|
'#type' => 'chart_yaxis',
|
||||||
|
'#title' => $this->t('Number of Installs'),
|
||||||
|
],
|
||||||
|
'#stacking' => TRUE,
|
||||||
|
];
|
||||||
|
if ($library === 'chartjs') {
|
||||||
|
// A real-life #raw_options use-case.
|
||||||
|
$charts_container['content']['from_csv_file']['#raw_options'] = [
|
||||||
|
'options' => [
|
||||||
|
'scales' => [
|
||||||
|
'x' => [
|
||||||
|
'ticks' => [
|
||||||
|
'autoSkip' => TRUE,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
elseif ($library === 'billboard' || $library === 'c3') {
|
||||||
|
$charts_container['content']['from_csv_file']['#raw_options'] = [
|
||||||
|
'axis' => [
|
||||||
|
'x' => [
|
||||||
|
'tick' => [
|
||||||
|
'culling' => TRUE,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stacked column chart with two series.
|
||||||
|
$charts_container['content']['stacked_two_series_column'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Stacked Column Chart (Two Series)', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'column',
|
||||||
|
'series_one' => $series,
|
||||||
|
'series_two' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('8.x-3.x'),
|
||||||
|
'#data' => [4330, 4413, 4212, 4431],
|
||||||
|
'#color' => '#77b259',
|
||||||
|
],
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#stacking' => TRUE,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Combination chart (column and line).
|
||||||
|
$charts_container['content']['combo'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Combination Chart', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'column',
|
||||||
|
'series_one' => $series,
|
||||||
|
'series_two' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#chart_type' => 'line',
|
||||||
|
'#title' => $this->t('8.x-3.x'),
|
||||||
|
'#data' => [4330, 4413, 4212, 4431],
|
||||||
|
'#color' => '#77b259',
|
||||||
|
],
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Combination chart (column and line) with secondary Y-Axis.
|
||||||
|
$charts_container['content']['combo_dual_yaxes'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Combination Chart with Secondary Y-Axis', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'column',
|
||||||
|
'series_one' => $series,
|
||||||
|
'series_two' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#chart_type' => 'line',
|
||||||
|
'#title' => $this->t('8.x-3.x'),
|
||||||
|
'#data' => [4330, 4413, 4212, 4431],
|
||||||
|
'#color' => '#77b259',
|
||||||
|
'#target_axis' => 'y_axis_secondary',
|
||||||
|
],
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'y_axis_secondary' => [
|
||||||
|
'#type' => 'chart_yaxis',
|
||||||
|
'#title' => $this->t('Secondary Y-Axis'),
|
||||||
|
'#opposite' => TRUE,
|
||||||
|
],
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Radar chart. Not supported by C3.js or Google Charts (natively).
|
||||||
|
if (!in_array($library, ['c3', 'google'])) {
|
||||||
|
$charts_container['content']['radar'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Radar Chart', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'line',
|
||||||
|
'series' => $series,
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#polar' => TRUE,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gauge chart. Not yet supported by Chart.js (as of 3.5.1).
|
||||||
|
if ($library !== 'chartjs') {
|
||||||
|
$charts_container['content']['gauge'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#title' => $this->t('@library Gauge Chart', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'gauge',
|
||||||
|
'#gauge' => [
|
||||||
|
'green_to' => 100,
|
||||||
|
'green_from' => 75,
|
||||||
|
'yellow_to' => 74,
|
||||||
|
'yellow_from' => 50,
|
||||||
|
'red_to' => 49,
|
||||||
|
'red_from' => 0,
|
||||||
|
'max' => 100,
|
||||||
|
'min' => 0,
|
||||||
|
],
|
||||||
|
'series' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('Speed'),
|
||||||
|
'#data' => [65],
|
||||||
|
],
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scatter chart.
|
||||||
|
$charts_container['content']['scatter'] = [
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Scatter Chart', ['@library' => ucfirst($library)]),
|
||||||
|
'#data_markers' => TRUE,
|
||||||
|
'#chart_type' => 'scatter',
|
||||||
|
'series' => [
|
||||||
|
'#type' => 'chart_data',
|
||||||
|
'#title' => $this->t('Group 1'),
|
||||||
|
'#data' => [[162.2, 51.8], [164.5, 58.0], [160.5, 49.6], [154.0, 65.0]],
|
||||||
|
],
|
||||||
|
'x_axis' => [
|
||||||
|
'#type' => 'chart_xaxis',
|
||||||
|
'#title' => $this->t('Height'),
|
||||||
|
'#labels' => [],
|
||||||
|
],
|
||||||
|
'y_axis' => [
|
||||||
|
'#type' => 'chart_yaxis',
|
||||||
|
'#title' => $this->t('Weight'),
|
||||||
|
],
|
||||||
|
'#stacking' => TRUE,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($library === 'highcharts') {
|
||||||
|
$charts_container['content']['php_override'] = [
|
||||||
|
'#chart_id' => 'exampleidphp',
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Chart, Overridden By PHP Hook', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'column',
|
||||||
|
'series' => $series,
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#color_changer' => TRUE,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
$charts_container['content']['js_override'] = [
|
||||||
|
'#id' => 'exampleidjs',
|
||||||
|
'#chart_id' => 'exampleidjschart',
|
||||||
|
'#type' => 'chart',
|
||||||
|
'#tooltips' => $charts_settings->get('charts_default_settings.display.tooltips'),
|
||||||
|
'#title' => $this->t('@library Chart, Overridden By JS Function', ['@library' => ucfirst($library)]),
|
||||||
|
'#chart_type' => 'column',
|
||||||
|
'series' => $series,
|
||||||
|
'x_axis' => $xaxis,
|
||||||
|
'y_axis' => $yaxis,
|
||||||
|
'#raw_options' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $charts_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the CSV contents in an array with data organized by column.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The array of rows.
|
||||||
|
*/
|
||||||
|
private function getCsvContents() {
|
||||||
|
$file_path = $this->moduleList->getPath('charts_api_example');
|
||||||
|
$file_name = $file_path . '/fixtures/charts_api_example_file.csv';
|
||||||
|
$handle = fopen($file_name, 'r');
|
||||||
|
$all_rows = [];
|
||||||
|
while ($row = fgetcsv($handle)) {
|
||||||
|
$all_rows['Week'][] = $row[0];
|
||||||
|
$all_rows['7.x-2.x'][] = (int) $row[4];
|
||||||
|
$all_rows['8.x-3.x'][] = (int) $row[6];
|
||||||
|
$all_rows['5.0.x'][] = (int) $row[8];
|
||||||
|
}
|
||||||
|
fclose($handle);
|
||||||
|
|
||||||
|
return $all_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
117
web/modules/charts/modules/charts_billboard/README.md
Executable file
117
web/modules/charts/modules/charts_billboard/README.md
Executable file
@@ -0,0 +1,117 @@
|
|||||||
|
#Installation Using Composer (recommended)
|
||||||
|
|
||||||
|
If you use Composer to manage dependencies, edit your site's "composer.json"
|
||||||
|
file as follows.
|
||||||
|
|
||||||
|
1. Run the following command to ensure that you have the "composer/installers"
|
||||||
|
package installed. This package facilitates the installation of packages into
|
||||||
|
directories other than "/vendor" (e.g. "/libraries") using Composer.
|
||||||
|
|
||||||
|
composer require --prefer-dist composer/installers
|
||||||
|
|
||||||
|
2. Add the following to the "installer-paths" section of "composer.json":
|
||||||
|
|
||||||
|
"libraries/{$name}": ["type:drupal-library"],
|
||||||
|
|
||||||
|
3. Add the following to the "repositories" section of "composer.json":
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "billboardjs/billboard",
|
||||||
|
"version": "3.10.3",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "billboard"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://registry.npmjs.org/billboard.js/-/billboard.js-3.10.3.tgz",
|
||||||
|
"type": "tar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "d3/d3",
|
||||||
|
"version": "7.8.5",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "d3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.js",
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
4. This and the following step is optional but recommended. The reason for
|
||||||
|
them is that when installing the Billboard.js package with Composer,
|
||||||
|
additional files are added into the library directory. These files are not
|
||||||
|
necessary and can be potentially harmful to your site, so it's best to remove
|
||||||
|
them. So: create a new directory in your project root called "scripts".
|
||||||
|
5. Inside that directory, create a new file called "clean-billboardjs.sh" and
|
||||||
|
paste the following into it:
|
||||||
|
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
declare -a directories=(
|
||||||
|
"web/libraries/billboard/dist-esm"
|
||||||
|
"web/libraries/billboard/src"
|
||||||
|
"web/libraries/billboard/types"
|
||||||
|
"web/libraries/billboard/dist/plugin"
|
||||||
|
"web/libraries/billboard/dist/theme"
|
||||||
|
)
|
||||||
|
counter=0
|
||||||
|
echo "Deleting unneeded directories inside web/libraries/billboard"
|
||||||
|
for directory in "${directories[@]}"
|
||||||
|
do
|
||||||
|
if [ -d $directory ]; then
|
||||||
|
echo "Deleting $directory"
|
||||||
|
rm -rf $directory
|
||||||
|
counter=$((counter+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$counter folders were deleted"
|
||||||
|
declare -a files=(
|
||||||
|
"web/libraries/billboard/CONTRIBUTING.md"
|
||||||
|
"web/libraries/billboard/README.md"
|
||||||
|
"web/libraries/billboard/LICENSE"
|
||||||
|
"web/libraries/billboard/package.json"
|
||||||
|
"web/libraries/billboard/dist/package.json"
|
||||||
|
)
|
||||||
|
counter=0
|
||||||
|
echo "Deleting unneeded files inside web/libraries/billboard"
|
||||||
|
for file in "${files[@]}"
|
||||||
|
do
|
||||||
|
if [[ -f $file ]]; then
|
||||||
|
echo "Deleting $file"
|
||||||
|
rm $file
|
||||||
|
counter=$((counter+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$counter files were deleted"
|
||||||
|
|
||||||
|
6. Add a "scripts" entry to your "composer.json" file as shown below. If
|
||||||
|
"scripts" already exists, you will need to do a little more to incorporate
|
||||||
|
the code below.
|
||||||
|
|
||||||
|
"scripts": {
|
||||||
|
"clean-billboardjs": "chmod +x scripts/clean-billboardjs.sh &&
|
||||||
|
./scripts/clean-billboardjs.sh",
|
||||||
|
"post-install-cmd": [
|
||||||
|
"@clean-billboardjs"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@clean-billboardjs"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
7. Run the following command; you should find that new directories have been
|
||||||
|
created under "/libraries".
|
||||||
|
|
||||||
|
composer require --prefer-dist billboardjs/billboard:3.10.3 d3/d3:7.8.5
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
name: 'Billboard.js Charts'
|
||||||
|
type: module
|
||||||
|
description: 'Charts module integration with Billboard.js Charts.'
|
||||||
|
package: Charts
|
||||||
|
core_version_requirement: ^10.3 || ^11
|
||||||
|
dependencies:
|
||||||
|
- 'charts:charts'
|
||||||
|
|
||||||
|
# Information added by Drupal.org packaging script on 2024-12-02
|
||||||
|
version: '5.1.1'
|
||||||
|
project: 'charts'
|
||||||
|
datestamp: 1733170633
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Installation and uninstallation functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_requirements().
|
||||||
|
*/
|
||||||
|
function charts_billboard_requirements($phase) {
|
||||||
|
$requirements = [];
|
||||||
|
|
||||||
|
switch ($phase) {
|
||||||
|
case 'runtime':
|
||||||
|
$library_path = charts_billboard_find_library();
|
||||||
|
$config = \Drupal::config('charts.settings');
|
||||||
|
$cdn = $config->get('advanced.requirements.cdn') ?? FALSE;
|
||||||
|
|
||||||
|
if (!$library_path) {
|
||||||
|
if ($cdn) {
|
||||||
|
$requirements['charts_billboard_js'] = [
|
||||||
|
'title' => t('Billboard.js Library'),
|
||||||
|
'value' => t('Available through a CDN'),
|
||||||
|
'severity' => REQUIREMENT_WARNING,
|
||||||
|
'description' => t('You are using the Billboard.js library via a content delivery network. It is generally considered better practice to install the library files locally. Please see the README file inside charts_billboard for instructions to install the library.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$requirements['charts_billboard_js'] = [
|
||||||
|
'title' => t('Billboard.js Library'),
|
||||||
|
'value' => t('Not Installed'),
|
||||||
|
'severity' => REQUIREMENT_ERROR,
|
||||||
|
'description' => t('You are missing the Billboard.js library in your Drupal installation directory and you have opted not to use a CDN. Please either enable use of the CDN in the Chart Settings under the Advanced tab or see the README file inside charts_billboard for instructions to install the library.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If the library directory contains a demo directory, warn.
|
||||||
|
if (file_exists($library_path . '/src')) {
|
||||||
|
$requirements['charts_billboard_js'] = [
|
||||||
|
'title' => t('Billboard.js Library'),
|
||||||
|
'value' => t('Installed'),
|
||||||
|
'severity' => REQUIREMENT_WARNING,
|
||||||
|
'description' => t('You have installed the Billboard.js library in your Drupal installation directory, but it contains additional files that are not required and may be harmful. Please delete everything except the files listed in charts_billboard.libraries.yml. We have included a suggested post-install/post-update script in the README file.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$requirements['charts_billboard_js'] = [
|
||||||
|
'title' => t('Billboard.js Library'),
|
||||||
|
'value' => t('Installed'),
|
||||||
|
'severity' => REQUIREMENT_OK,
|
||||||
|
'description' => t('You have installed the Billboard.js library in your Drupal installation directory.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the location of the Billboard.js library.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The location of the library, or FALSE if the library isn't installed.
|
||||||
|
*/
|
||||||
|
function charts_billboard_find_library() {
|
||||||
|
// The following logic is taken from libraries_get_libraries()
|
||||||
|
$searchdir = [];
|
||||||
|
|
||||||
|
// Similar to 'modules' and 'themes' directories inside an installation
|
||||||
|
// profile, installation profiles may want to place libraries into a
|
||||||
|
// 'libraries' directory.
|
||||||
|
$searchdir[] = 'profiles/' . \Drupal::installProfile() . '/libraries';
|
||||||
|
|
||||||
|
// Always search libraries.
|
||||||
|
$searchdir[] = 'libraries';
|
||||||
|
|
||||||
|
// Also search sites/<domain>/*.
|
||||||
|
$container = \Drupal::getContainer();
|
||||||
|
$site_path = $container->getParameter('site.path');
|
||||||
|
$site_path = explode('/', $site_path);
|
||||||
|
$site_name = $site_path[1];
|
||||||
|
$searchdir[] = $site_name . '/libraries';
|
||||||
|
|
||||||
|
foreach ($searchdir as $dir) {
|
||||||
|
if (file_exists($dir . '/billboard/dist/billboard.min.js') || file_exists($dir . '/billboard/dist/billboard.js')) {
|
||||||
|
return $dir . '/billboard';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
36
web/modules/charts/modules/charts_billboard/charts_billboard.libraries.yml
Executable file
36
web/modules/charts/modules/charts_billboard/charts_billboard.libraries.yml
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
charts_billboard:
|
||||||
|
version: 1.x
|
||||||
|
js:
|
||||||
|
js/charts_billboard.js: { weight: -1 }
|
||||||
|
dependencies:
|
||||||
|
- charts/global
|
||||||
|
- core/drupal
|
||||||
|
- core/once
|
||||||
|
d3:
|
||||||
|
remote: 'https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js'
|
||||||
|
version: 7.8.5
|
||||||
|
license:
|
||||||
|
name: BSD
|
||||||
|
url: 'https://en.wikipedia.org/wiki/BSD_licenses'
|
||||||
|
gpl-compatible: false
|
||||||
|
cdn:
|
||||||
|
/libraries/d3/: https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/
|
||||||
|
js:
|
||||||
|
/libraries/d3/d3.min.js: { minified: true }
|
||||||
|
billboard:
|
||||||
|
remote: 'https://naver.github.io/billboard.js/release/3.10.3/dist/billboard.min.js'
|
||||||
|
version: 3.10.3
|
||||||
|
license:
|
||||||
|
name: MIT
|
||||||
|
url: 'https://opensource.org/licenses/MIT'
|
||||||
|
gpl-compatible: true
|
||||||
|
cdn:
|
||||||
|
/libraries/billboard/: https://naver.github.io/billboard.js/release/3.10.3/
|
||||||
|
css:
|
||||||
|
theme:
|
||||||
|
/libraries/billboard/dist/billboard.min.css: { minified: true }
|
||||||
|
js:
|
||||||
|
/libraries/billboard/dist/billboard.min.js: { minified: true }
|
||||||
|
dependencies:
|
||||||
|
- charts_billboard/charts_billboard
|
||||||
|
- charts_billboard/d3
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Implement module related hooks for the charts_billboard module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_charts_version3_to_new_settings_structure_alter().
|
||||||
|
*/
|
||||||
|
function charts_billboard_charts_version3_to_new_settings_structure_alter(array &$new_settings, string $for) {
|
||||||
|
$config_factory = \Drupal::configFactory();
|
||||||
|
$billboard_config = $config_factory->getEditable('charts_billboard.settings');
|
||||||
|
if ($billboard_config) {
|
||||||
|
$billboard_config->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
web/modules/charts/modules/charts_billboard/composer.json
Executable file
49
web/modules/charts/modules/charts_billboard/composer.json
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "drupal/charts_billboard",
|
||||||
|
"description": "Charts module integration with Billboard.js Charts.",
|
||||||
|
"type": "drupal-module",
|
||||||
|
"homepage": "http://drupal.org/project/charts",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://www.drupal.org/project/issues/charts"
|
||||||
|
},
|
||||||
|
"license": "GPL-2.0+",
|
||||||
|
"require": {
|
||||||
|
"billboardjs/billboard": "3.10.3",
|
||||||
|
"d3/d3": "7.8.5"
|
||||||
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "billboardjs/billboard",
|
||||||
|
"version": "3.10.3",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "billboard"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://github.com/naver/billboard.js/archive/3.10.3.zip",
|
||||||
|
"type": "zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "d3/d3",
|
||||||
|
"version": "7.8.5",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "d3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js",
|
||||||
|
"type": "file"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
web/modules/charts/modules/charts_billboard/js/charts_billboard.js
Executable file
26
web/modules/charts/modules/charts_billboard/js/charts_billboard.js
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* JavaScript integration between Billboard and Drupal.
|
||||||
|
*/
|
||||||
|
(function (Drupal, once) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Drupal.behaviors.chartsBillboard = {
|
||||||
|
attach: function (context, settings) {
|
||||||
|
const contents = new Drupal.Charts.Contents();
|
||||||
|
once('charts-billboard', '.charts-billboard', context).forEach(function (element) {
|
||||||
|
const config = contents.getData(element.id);
|
||||||
|
const title = config.title.text;
|
||||||
|
// If the title contains '\\n', convert it to a line break.
|
||||||
|
if (title.indexOf('\\n') !== -1) {
|
||||||
|
config.title.text = title.replace(/\\n/g, '\n');
|
||||||
|
}
|
||||||
|
bb.generate(config);
|
||||||
|
if (element.nextElementSibling && element.nextElementSibling.hasAttribute('data-charts-debug-container')) {
|
||||||
|
element.nextElementSibling.querySelector('code').innerText = JSON.stringify(config, null, ' ');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}(Drupal, once));
|
||||||
@@ -0,0 +1,454 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\charts_billboard\Plugin\chart\Library;
|
||||||
|
|
||||||
|
use Drupal\charts\Plugin\chart\Library\ChartBase;
|
||||||
|
use Drupal\Component\Utility\Html;
|
||||||
|
use Drupal\Component\Utility\NestedArray;
|
||||||
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||||
|
use Drupal\Core\Render\Element;
|
||||||
|
use Drupal\Core\Render\ElementInfoManagerInterface;
|
||||||
|
use Drupal\Core\Url;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a concrete class for a Chart.
|
||||||
|
*
|
||||||
|
* @Chart(
|
||||||
|
* id = "billboard",
|
||||||
|
* name = @Translation("Billboard.js"),
|
||||||
|
* types = {
|
||||||
|
* "area",
|
||||||
|
* "bar",
|
||||||
|
* "bubble",
|
||||||
|
* "column",
|
||||||
|
* "donut",
|
||||||
|
* "gauge",
|
||||||
|
* "line",
|
||||||
|
* "pie",
|
||||||
|
* "scatter",
|
||||||
|
* "spline",
|
||||||
|
* },
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class Billboard extends ChartBase implements ContainerFactoryPluginInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The element info manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Render\ElementInfoManagerInterface
|
||||||
|
*/
|
||||||
|
protected $elementInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a \Drupal\views\Plugin\Block\ViewsBlockBase object.
|
||||||
|
*
|
||||||
|
* @param array $configuration
|
||||||
|
* A configuration array containing information about the plugin instance.
|
||||||
|
* @param string $plugin_id
|
||||||
|
* The plugin_id for the plugin instance.
|
||||||
|
* @param mixed $plugin_definition
|
||||||
|
* The plugin implementation definition.
|
||||||
|
* @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
|
||||||
|
* The element info manager.
|
||||||
|
*/
|
||||||
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, ElementInfoManagerInterface $element_info) {
|
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
|
$this->elementInfo = $element_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||||
|
return new static(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$container->get('element_info')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||||
|
$form = parent::buildConfigurationForm($form, $form_state);
|
||||||
|
$form['intro_text'] = [
|
||||||
|
'#markup' => $this->t('This is a placeholder for Billboard.js-specific library options. If you would like to help build this out, please work from <a href="@issue_link">this issue</a>.', [
|
||||||
|
'@issue_link' => Url::fromUri('https://www.drupal.org/project/charts/issues/3046983')->toString(),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function preRender(array $element) {
|
||||||
|
// Populate chart settings.
|
||||||
|
$chart_definition = [];
|
||||||
|
|
||||||
|
$chart_definition = $this->populateOptions($element, $chart_definition);
|
||||||
|
$chart_definition = $this->populateData($element, $chart_definition);
|
||||||
|
$chart_definition = $this->populateAxes($element, $chart_definition);
|
||||||
|
|
||||||
|
if (!empty($element['#height']) || !empty($element['#width'])) {
|
||||||
|
$element['#attributes']['style'] = 'height:' . $element['#height'] . $element['#height_units'] . ';width:' . $element['#width'] . $element['#width_units'] . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($element['#id'])) {
|
||||||
|
$element['#id'] = Html::getUniqueId('chart-billboard');
|
||||||
|
}
|
||||||
|
$chart_definition['bindto'] = '#' . $element['#id'];
|
||||||
|
|
||||||
|
$element['#attached']['library'][] = 'charts_billboard/billboard';
|
||||||
|
$element['#attributes']['class'][] = 'charts-billboard charts-bb';
|
||||||
|
$element['#chart_definition'] = $chart_definition;
|
||||||
|
|
||||||
|
return $element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the chart type.
|
||||||
|
*
|
||||||
|
* @param string $chart_type
|
||||||
|
* The chart type.
|
||||||
|
* @param bool $is_polar
|
||||||
|
* Whether the polar is checked.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The chart type.
|
||||||
|
*/
|
||||||
|
protected function getType($chart_type, $is_polar = FALSE) {
|
||||||
|
// If Polar is checked, then convert to Radar chart type.
|
||||||
|
if ($is_polar) {
|
||||||
|
$type = 'radar';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$type = $chart_type == 'column' ? 'bar' : $chart_type;
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get options.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* The chart type.
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The returned options.
|
||||||
|
*/
|
||||||
|
protected function getOptionsByType($type, array $element) {
|
||||||
|
$options = $this->getOptionsByCustomProperty($element, $type);
|
||||||
|
if ($type === 'bar') {
|
||||||
|
$options['width'] = $element['#width'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the options by custom property.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param string $type
|
||||||
|
* The chart type.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* The return options.
|
||||||
|
*/
|
||||||
|
protected function getOptionsByCustomProperty(array $element, $type) {
|
||||||
|
$options = [];
|
||||||
|
$properties = Element::properties($element);
|
||||||
|
// Remove properties which are not related to this chart type.
|
||||||
|
$properties = array_filter($properties, function ($property) use ($type) {
|
||||||
|
$query = '#chart_' . $type . '_';
|
||||||
|
return substr($property, 0, strlen($query)) === $query;
|
||||||
|
});
|
||||||
|
foreach ($properties as $property) {
|
||||||
|
$query = '#chart_' . $type . '_';
|
||||||
|
$option_key = substr($property, strlen($query), strlen($property));
|
||||||
|
$options[$option_key] = $element[$property];
|
||||||
|
}
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate options.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the chart definition.
|
||||||
|
*/
|
||||||
|
private function populateOptions(array $element, array $chart_definition) {
|
||||||
|
$type = $this->getType($element['#chart_type'], $element['#polar'] ?? FALSE);
|
||||||
|
$title = $element['#title'] ?? '';
|
||||||
|
if (!empty($element['#subtitle'])) {
|
||||||
|
$title .= '\n' . $element['#subtitle'];
|
||||||
|
}
|
||||||
|
$chart_definition['title']['text'] = $title;
|
||||||
|
$chart_definition['legend']['show'] = !empty($element['#legend_position']);
|
||||||
|
if (!in_array($type, ['scatter', 'bubble'])) {
|
||||||
|
$chart_definition['axis']['x']['type'] = 'category';
|
||||||
|
}
|
||||||
|
$chart_definition['data']['labels'] = (bool) $element['#data_labels'];
|
||||||
|
|
||||||
|
if ($type === 'pie' || $type === 'donut') {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
elseif ($type === 'gauge') {
|
||||||
|
$chart_definition['gauge']['min'] = $element['#gauge']['min'];
|
||||||
|
$chart_definition['gauge']['max'] = $element['#gauge']['max'];
|
||||||
|
$chart_definition['color']['pattern'] = [
|
||||||
|
'red',
|
||||||
|
'yellow',
|
||||||
|
'green',
|
||||||
|
];
|
||||||
|
$chart_definition['color']['threshold']['values'] = [
|
||||||
|
$element['#gauge']['red_from'],
|
||||||
|
$element['#gauge']['yellow_from'],
|
||||||
|
$element['#gauge']['green_from'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
elseif ($type === 'line' || $type === 'spline') {
|
||||||
|
$chart_definition['point']['show'] = !empty($element['#data_markers']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* Billboard does not use bar, so column must be used. Since 'column'
|
||||||
|
* is changed
|
||||||
|
* to 'bar' in getType(), we need to use the value from the element.
|
||||||
|
*/
|
||||||
|
if ($element['#chart_type'] === 'bar') {
|
||||||
|
$chart_definition['axis']['rotated'] = TRUE;
|
||||||
|
}
|
||||||
|
elseif ($element['#chart_type'] === 'column') {
|
||||||
|
$type = 'bar';
|
||||||
|
$chart_definition['axis']['rotated'] = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$chart_definition['data']['type'] = $type;
|
||||||
|
// Merge in chart raw options.
|
||||||
|
if (!empty($element['#raw_options'])) {
|
||||||
|
$chart_definition = NestedArray::mergeDeepArray([
|
||||||
|
$chart_definition,
|
||||||
|
$element['#raw_options'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chart_definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate axes.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the chart definition.
|
||||||
|
*/
|
||||||
|
private function populateAxes(array $element, array $chart_definition) {
|
||||||
|
$children = Element::children($element);
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$type = $element[$child]['#type'];
|
||||||
|
if ($type === 'chart_xaxis') {
|
||||||
|
$chart_definition['axis']['x']['label'] = $element[$child]['#title'] ?? '';
|
||||||
|
$chart_type = $this->getType($element['#chart_type']);
|
||||||
|
$categories = $this->stripLabelTags($element[$child]['#labels']);
|
||||||
|
if (!in_array($chart_type, ['pie', 'donut'])) {
|
||||||
|
if ($chart_type === 'scatter' || $chart_type === 'bubble') {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$chart_definition['data']['columns'][] = ['x'];
|
||||||
|
$chart_definition['data']['x'] = 'x';
|
||||||
|
$categories_keys = array_keys($chart_definition['data']['columns']);
|
||||||
|
$categories_key = end($categories_keys);
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$chart_definition['data']['columns'][$categories_key][] = $category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$chart_definition['data']['columns'] = array_map(NULL, $categories, $chart_definition['data']['columns']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($type === 'chart_yaxis') {
|
||||||
|
if (!empty($element[$child]['#opposite']) && $element[$child]['#opposite'] === TRUE) {
|
||||||
|
$chart_definition['axis']['y2']['show'] = TRUE;
|
||||||
|
$this->setLabelMinMax($chart_definition, 'y2', $element[$child]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->setLabelMinMax($chart_definition, 'y', $element[$child]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chart_definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the label, min, and max.
|
||||||
|
*
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
* @param string $axis
|
||||||
|
* The axis.
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
*/
|
||||||
|
private function setLabelMinMax(array &$chart_definition, string $axis, array $element): void {
|
||||||
|
$chart_definition['axis'][$axis]['label'] = $element['#title'] ?? '';
|
||||||
|
if (!empty($element['#min'])) {
|
||||||
|
$chart_definition['axis'][$axis]['min'] = $element['#min'];
|
||||||
|
}
|
||||||
|
if (!empty($element['#max'])) {
|
||||||
|
$chart_definition['axis'][$axis]['max'] = $element['#max'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate data.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the chart definition.
|
||||||
|
*/
|
||||||
|
private function populateData(array &$element, array $chart_definition) {
|
||||||
|
$type = $this->getType($element['#chart_type'], $element['#polar'] ?? FALSE);
|
||||||
|
$types = [];
|
||||||
|
$children = Element::children($element);
|
||||||
|
$y_axes = [];
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$element_type = $element[$child]['#type'];
|
||||||
|
if ($element_type === 'chart_yaxis') {
|
||||||
|
$y_axes[] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data_elements = array_filter($children, function ($child) use ($element) {
|
||||||
|
return $element[$child]['#type'] === 'chart_data';
|
||||||
|
});
|
||||||
|
|
||||||
|
$columns = $chart_definition['data']['columns'] ?? [];
|
||||||
|
$column_keys = array_keys($columns);
|
||||||
|
$columns_key_start = $columns ? end($column_keys) + 1 : 0;
|
||||||
|
foreach ($data_elements as $key) {
|
||||||
|
$child_element = $element[$key];
|
||||||
|
// Make sure defaults are loaded.
|
||||||
|
if (empty($child_element['#defaults_loaded'])) {
|
||||||
|
$child_element += $this->elementInfo->getInfo($child_element['#type']);
|
||||||
|
}
|
||||||
|
if ($child_element['#color'] && $type !== 'gauge') {
|
||||||
|
$chart_definition['color']['pattern'][] = $child_element['#color'];
|
||||||
|
}
|
||||||
|
if (!in_array($type, ['pie', 'donut'])) {
|
||||||
|
$series_title = isset($child_element['#title']) ? strip_tags($child_element['#title']) : '';
|
||||||
|
$types[$series_title] = $child_element['#chart_type'] ? $this->getType($child_element['#chart_type'], $element['#polar'] ?? FALSE) : $type;
|
||||||
|
if (!in_array($type, ['scatter', 'bubble'])) {
|
||||||
|
$columns[$columns_key_start][] = $series_title;
|
||||||
|
foreach ($child_element['#data'] as $datum) {
|
||||||
|
if (gettype($datum) === 'array') {
|
||||||
|
if ($type === 'gauge') {
|
||||||
|
array_shift($datum);
|
||||||
|
}
|
||||||
|
$columns[$columns_key_start][] = array_map(function ($item) {
|
||||||
|
return isset($item) ? strip_tags($item) : NULL;
|
||||||
|
}, $datum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$columns[$columns_key_start][] = isset($datum) ? strip_tags($datum) : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$row = [];
|
||||||
|
$row[$series_title][0] = $series_title;
|
||||||
|
$row[$series_title . '_x'][0] = $series_title . '_x';
|
||||||
|
foreach ($child_element['#data'] as $datum) {
|
||||||
|
$row[$series_title][] = $datum[0];
|
||||||
|
$row[$series_title . '_x'][] = $datum[1];
|
||||||
|
}
|
||||||
|
$chart_definition['data']['xs'][$series_title] = $series_title . '_x';
|
||||||
|
foreach ($row as $value) {
|
||||||
|
$columns[] = $value;
|
||||||
|
}
|
||||||
|
$columns = array_values($columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach ($child_element['#data'] as $datum_index => $datum) {
|
||||||
|
if (!empty($datum['color'])) {
|
||||||
|
$chart_definition['color']['pattern'][$datum_index] = $datum['color'];
|
||||||
|
unset($datum['color']);
|
||||||
|
$datum = array_values($datum);
|
||||||
|
}
|
||||||
|
$columns[] = $datum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add colors for each segment.
|
||||||
|
foreach ($child_element['#grouping_colors'] ?? [] as $key => $colors_array) {
|
||||||
|
$color = reset($colors_array);
|
||||||
|
$chart_definition['color']['pattern'][$key] = $color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns_key_start++;
|
||||||
|
}
|
||||||
|
if ($element['#stacking']) {
|
||||||
|
$chart_definition['data']['groups'] = [array_keys($types)];
|
||||||
|
}
|
||||||
|
$chart_definition['data']['types'] = $types;
|
||||||
|
$chart_definition['data']['columns'] = $columns;
|
||||||
|
|
||||||
|
if (count($y_axes) >= 2) {
|
||||||
|
foreach ($columns as $index => $column) {
|
||||||
|
if ($index <= 1) {
|
||||||
|
$axis = ($index + 1) === 2 ? 2 : '';
|
||||||
|
$chart_definition['data']['axes'][$column[0]] = 'y' . $axis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chart_definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip tags from each item in an array.
|
||||||
|
*
|
||||||
|
* @param array $items
|
||||||
|
* The array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the cleaned array.
|
||||||
|
*/
|
||||||
|
private function stripLabelTags(array $items): array {
|
||||||
|
if (empty($items)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$categories = [];
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$categories[] = isset($item) ? strip_tags($item) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
9
web/modules/charts/modules/charts_blocks/README.md
Normal file
9
web/modules/charts/modules/charts_blocks/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#Charts Blocks
|
||||||
|
|
||||||
|
Use this module if you would like a chart added via Layout Builder or the
|
||||||
|
"Block layout" page. You will need to enable at least one charting provider
|
||||||
|
submodule before this module can be used. Data can be added manually or by
|
||||||
|
uploading a CSV file.
|
||||||
|
|
||||||
|
If you create your chart using a View, you do not need this module - just add
|
||||||
|
a "Block" display to your View.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
name: Charts Blocks
|
||||||
|
type: module
|
||||||
|
description: Create Charts blocks without the need for Views.
|
||||||
|
core_version_requirement: ^10.3 || ^11
|
||||||
|
package: Charts
|
||||||
|
dependencies:
|
||||||
|
- drupal:charts
|
||||||
|
|
||||||
|
# Information added by Drupal.org packaging script on 2024-12-02
|
||||||
|
version: '5.1.1'
|
||||||
|
project: 'charts'
|
||||||
|
datestamp: 1733170633
|
||||||
24
web/modules/charts/modules/charts_blocks/charts_blocks.module
Executable file
24
web/modules/charts/modules/charts_blocks/charts_blocks.module
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains chart_block_example.module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Drupal\Core\Routing\RouteMatchInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_help().
|
||||||
|
*/
|
||||||
|
function charts_blocks_help($route_name, RouteMatchInterface $route_match) {
|
||||||
|
switch ($route_name) {
|
||||||
|
// Main module help for the charts_blocks module.
|
||||||
|
case 'help.page.charts_blocks':
|
||||||
|
$output = '';
|
||||||
|
$output .= '<h3>' . t('About') . '</h3>';
|
||||||
|
$output .= '<p>' . t('Create Charts blocks without the need for Views.') . '</p>';
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
114
web/modules/charts/modules/charts_blocks/src/Plugin/Block/ChartsBlock.php
Executable file
114
web/modules/charts/modules/charts_blocks/src/Plugin/Block/ChartsBlock.php
Executable file
@@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\charts_blocks\Plugin\Block;
|
||||||
|
|
||||||
|
use Drupal\charts\Element\Chart;
|
||||||
|
use Drupal\Component\Utility\NestedArray;
|
||||||
|
use Drupal\Component\Uuid\UuidInterface;
|
||||||
|
use Drupal\Core\Block\BlockBase;
|
||||||
|
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||||
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a 'ChartsBlock' block.
|
||||||
|
*
|
||||||
|
* @Block(
|
||||||
|
* id = "charts_block",
|
||||||
|
* admin_label = @Translation("Charts block"),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class ChartsBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The config factory service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||||
|
*/
|
||||||
|
protected $configFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UUID service.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Component\Uuid\UuidInterface
|
||||||
|
*/
|
||||||
|
protected $uuidService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory, UuidInterface $uuidService) {
|
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
|
$this->setConfiguration($configuration);
|
||||||
|
$this->configFactory = $config_factory;
|
||||||
|
$this->uuidService = $uuidService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||||
|
return new static(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$container->get('config.factory'),
|
||||||
|
$container->get('uuid')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function blockForm($form, FormStateInterface $form_state) {
|
||||||
|
parent::blockForm($form, $form_state);
|
||||||
|
|
||||||
|
$chart_block_configurations = !empty($this->configuration['chart']) ? $this->configuration['chart'] : [];
|
||||||
|
|
||||||
|
// Merge the charts default settings with this block's configuration.
|
||||||
|
$charts_settings = $this->configFactory->get('charts.settings');
|
||||||
|
$charts_default_settings = $charts_settings->get('charts_default_settings') ?? [];
|
||||||
|
$defaults = NestedArray::mergeDeep($charts_default_settings, $chart_block_configurations);
|
||||||
|
|
||||||
|
$form['chart'] = [
|
||||||
|
'#type' => 'details',
|
||||||
|
'#title' => $this->t('Chart configurations'),
|
||||||
|
'#open' => TRUE,
|
||||||
|
];
|
||||||
|
|
||||||
|
$form['chart']['settings'] = [
|
||||||
|
'#type' => 'charts_settings',
|
||||||
|
'#used_in' => 'basic_form',
|
||||||
|
'#required' => TRUE,
|
||||||
|
'#series' => TRUE,
|
||||||
|
'#default_value' => $defaults,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||||
|
$this->configuration['chart'] = $form_state->getValue(['chart', 'settings']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function build() {
|
||||||
|
$chart_settings = !empty($this->configuration['chart']) ? $this->configuration['chart'] : [];
|
||||||
|
|
||||||
|
// Creates a UUID for the chart ID.
|
||||||
|
$chart_id = 'charts_block__' . $this->configuration['id'];
|
||||||
|
$id = 'chart-' . $this->uuidService->generate();
|
||||||
|
$build = Chart::buildElement($chart_settings, $chart_id);
|
||||||
|
$build['#id'] = $id;
|
||||||
|
$build['#chart_id'] = $chart_id;
|
||||||
|
|
||||||
|
return $build;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
137
web/modules/charts/modules/charts_c3/README.md
Executable file
137
web/modules/charts/modules/charts_c3/README.md
Executable file
@@ -0,0 +1,137 @@
|
|||||||
|
#Installation Using Composer (recommended)
|
||||||
|
|
||||||
|
If you use Composer to manage dependencies, edit your site's "composer.json"
|
||||||
|
file as follows.
|
||||||
|
|
||||||
|
1. Run the following command to ensure that you have the "composer/installers"
|
||||||
|
package installed. This package facilitates the installation of packages into
|
||||||
|
directories other than "/vendor" (e.g. "/libraries") using Composer.
|
||||||
|
|
||||||
|
composer require --prefer-dist composer/installers
|
||||||
|
|
||||||
|
2. Add the following to the "installer-paths" section of "composer.json":
|
||||||
|
|
||||||
|
"libraries/{$name}": ["type:drupal-library"],
|
||||||
|
|
||||||
|
3. Add the following to the "repositories" section of "composer.json":
|
||||||
|
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "c3js/c3",
|
||||||
|
"version": "v0.7.20",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "c3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://github.com/c3js/c3/archive/v0.7.20.zip",
|
||||||
|
"type": "zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "d3/d3",
|
||||||
|
"version": "v4.9.1",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "d3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://github.com/d3/d3/archive/v4.9.1.zip",
|
||||||
|
"type": "zip"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
4. This and the following step is optional but recommended. The reason for
|
||||||
|
them is that when installing the C3.js package with Composer,
|
||||||
|
additional files are added into the library directory. These files are not
|
||||||
|
necessary and can be potentially harmful to your site, so it's best to remove
|
||||||
|
them. So: create a new directory in your project root called "scripts".
|
||||||
|
5. Inside that directory, create a new file called "clean-c3js.sh" and
|
||||||
|
paste the following into it:
|
||||||
|
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
declare -a directories=(
|
||||||
|
"web/libraries/c3/.circleci"
|
||||||
|
"web/libraries/c3/.github"
|
||||||
|
"web/libraries/c3/data"
|
||||||
|
"web/libraries/c3/design"
|
||||||
|
"web/libraries/c3/docs"
|
||||||
|
"web/libraries/c3/extensions"
|
||||||
|
"web/libraries/c3/htdocs"
|
||||||
|
"web/libraries/c3/spec"
|
||||||
|
"web/libraries/c3/src"
|
||||||
|
)
|
||||||
|
counter=0
|
||||||
|
echo "Deleting unneeded directories inside web/libraries/c3"
|
||||||
|
for directory in "${directories[@]}"
|
||||||
|
do
|
||||||
|
if [ -d $directory ]; then
|
||||||
|
echo "Deleting $directory"
|
||||||
|
rm -rf $directory
|
||||||
|
counter=$((counter+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$counter folders were deleted"
|
||||||
|
declare -a files=(
|
||||||
|
"web/libraries/c3/CONTRIBUTING.md"
|
||||||
|
"web/libraries/c3/README.md"
|
||||||
|
"web/libraries/c3/LICENSE"
|
||||||
|
"web/libraries/c3/package.json"
|
||||||
|
"web/libraries/c3/.bmp.yml"
|
||||||
|
"web/libraries/c3/.editorconfig"
|
||||||
|
"web/libraries/c3/.gitignore"
|
||||||
|
"web/libraries/c3/.jshintrc"
|
||||||
|
"web/libraries/c3/.prettierrc.json"
|
||||||
|
"web/libraries/c3/.travis.yml"
|
||||||
|
"web/libraries/c3/bower.json"
|
||||||
|
"web/libraries/c3/codecov.yml"
|
||||||
|
"web/libraries/c3/component.json"
|
||||||
|
"web/libraries/c3/config.rb"
|
||||||
|
"web/libraries/c3/Gemfile"
|
||||||
|
"web/libraries/c3/Gemfile.lock"
|
||||||
|
"web/libraries/c3/karma.conf.js"
|
||||||
|
"web/libraries/c3/MAINTAINANCE.md"
|
||||||
|
"web/libraries/c3/rollup.config.js"
|
||||||
|
"web/libraries/c3/tsconfig.json"
|
||||||
|
"web/libraries/c3/yarn.lock"
|
||||||
|
)
|
||||||
|
counter=0
|
||||||
|
echo "Deleting unneeded files inside web/libraries/c3"
|
||||||
|
for file in "${files[@]}"
|
||||||
|
do
|
||||||
|
if [[ -f $file ]]; then
|
||||||
|
echo "Deleting $file"
|
||||||
|
rm $file
|
||||||
|
counter=$((counter+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$counter files were deleted"
|
||||||
|
|
||||||
|
6. Add a "scripts" entry to your "composer.json" file as shown below. If
|
||||||
|
"scripts" already exists, you will need to do a little more to incorporate
|
||||||
|
the code below.
|
||||||
|
|
||||||
|
"scripts": {
|
||||||
|
"clean-c3js": "chmod +x scripts/clean-c3js.sh &&
|
||||||
|
./scripts/clean-c3js.sh",
|
||||||
|
"post-install-cmd": [
|
||||||
|
"@clean-c3js"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@clean-c3js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
7. Run the following command; you should find that new directories have been
|
||||||
|
created under "/libraries".
|
||||||
|
|
||||||
|
composer require --prefer-dist c3js/c3:0.7.20 d3/d3:4.9.1
|
||||||
12
web/modules/charts/modules/charts_c3/charts_c3.info.yml
Normal file
12
web/modules/charts/modules/charts_c3/charts_c3.info.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
name: 'C3.js Charts'
|
||||||
|
type: module
|
||||||
|
description: 'Charts module integration with C3.js Charts.'
|
||||||
|
package: Charts
|
||||||
|
core_version_requirement: ^10.3 || ^11
|
||||||
|
dependencies:
|
||||||
|
- 'charts:charts'
|
||||||
|
|
||||||
|
# Information added by Drupal.org packaging script on 2024-12-02
|
||||||
|
version: '5.1.1'
|
||||||
|
project: 'charts'
|
||||||
|
datestamp: 1733170633
|
||||||
95
web/modules/charts/modules/charts_c3/charts_c3.install
Normal file
95
web/modules/charts/modules/charts_c3/charts_c3.install
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Installation and uninstallation functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_requirements().
|
||||||
|
*/
|
||||||
|
function charts_c3_requirements($phase) {
|
||||||
|
$requirements = [];
|
||||||
|
|
||||||
|
switch ($phase) {
|
||||||
|
case 'runtime':
|
||||||
|
$library_path = charts_c3_find_library();
|
||||||
|
$config = \Drupal::config('charts.settings');
|
||||||
|
$cdn = $config->get('advanced.requirements.cdn') ?? FALSE;
|
||||||
|
|
||||||
|
if (!$library_path) {
|
||||||
|
if ($cdn) {
|
||||||
|
$requirements['charts_c3_js'] = [
|
||||||
|
'title' => t('C3.js Library'),
|
||||||
|
'value' => t('Available through a CDN'),
|
||||||
|
'severity' => REQUIREMENT_WARNING,
|
||||||
|
'description' => t('You are using the C3.js library via a content delivery network. It is generally considered better practice to install the library files locally. Please see the README file inside charts_c3 for instructions to install the library.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$requirements['charts_c3_js'] = [
|
||||||
|
'title' => t('C3.js Library'),
|
||||||
|
'value' => t('Not Installed'),
|
||||||
|
'severity' => REQUIREMENT_ERROR,
|
||||||
|
'description' => t('You are missing the C3.js library in your Drupal installation directory and you have opted not to use a CDN. Please either enable use of the CDN in the Chart Settings under the Advanced tab or see the README file inside charts_c3 for instructions to install the library.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If the library directory contains a demo directory, warn.
|
||||||
|
if (file_exists($library_path . '/src')) {
|
||||||
|
$requirements['charts_c3_js'] = [
|
||||||
|
'title' => t('C3.js Library'),
|
||||||
|
'value' => t('Installed'),
|
||||||
|
'severity' => REQUIREMENT_WARNING,
|
||||||
|
'description' => t('You have installed the C3.js library in your Drupal installation directory, but it contains additional files that are not required and may be harmful. Please delete everything except the files listed in charts_c3.libraries.yml. We have included a suggested post-install/post-update script in the README file.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$requirements['charts_c3_js'] = [
|
||||||
|
'title' => t('C3.js Library'),
|
||||||
|
'value' => t('Installed'),
|
||||||
|
'severity' => REQUIREMENT_OK,
|
||||||
|
'description' => t('You have installed the C3.js library in your Drupal installation directory.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the location of the C3.js library.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The location of the library, or FALSE if the library isn't installed.
|
||||||
|
*/
|
||||||
|
function charts_c3_find_library() {
|
||||||
|
// The following logic is taken from libraries_get_libraries()
|
||||||
|
$searchdir = [];
|
||||||
|
|
||||||
|
// Similar to 'modules' and 'themes' directories inside an installation
|
||||||
|
// profile, installation profiles may want to place libraries into a
|
||||||
|
// 'libraries' directory.
|
||||||
|
$searchdir[] = 'profiles/' . \Drupal::installProfile() . '/libraries';
|
||||||
|
|
||||||
|
// Always search libraries.
|
||||||
|
$searchdir[] = 'libraries';
|
||||||
|
|
||||||
|
// Also search sites/<domain>/*.
|
||||||
|
$container = \Drupal::getContainer();
|
||||||
|
$site_path = $container->getParameter('site.path');
|
||||||
|
$site_path = explode('/', $site_path);
|
||||||
|
$site_name = $site_path[1];
|
||||||
|
$searchdir[] = $site_name . '/libraries';
|
||||||
|
|
||||||
|
foreach ($searchdir as $dir) {
|
||||||
|
if (file_exists($dir . '/c3/c3.min.js') || file_exists($dir . '/c3/c3.js')) {
|
||||||
|
return $dir . '/c3';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
36
web/modules/charts/modules/charts_c3/charts_c3.libraries.yml
Executable file
36
web/modules/charts/modules/charts_c3/charts_c3.libraries.yml
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
charts_c3:
|
||||||
|
version: 1.x
|
||||||
|
js:
|
||||||
|
js/charts_c3.js: { weight: -1 }
|
||||||
|
dependencies:
|
||||||
|
- charts/global
|
||||||
|
- core/drupal
|
||||||
|
- core/once
|
||||||
|
d3:
|
||||||
|
remote: 'https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js'
|
||||||
|
version: 5.16.0
|
||||||
|
license:
|
||||||
|
name: BSD
|
||||||
|
url: 'https://en.wikipedia.org/wiki/BSD_licenses'
|
||||||
|
gpl-compatible: false
|
||||||
|
cdn:
|
||||||
|
/libraries/d3/: https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/
|
||||||
|
js:
|
||||||
|
/libraries/d3/d3.min.js: { }
|
||||||
|
c3:
|
||||||
|
remote: 'https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/c3.min.js'
|
||||||
|
version: 0.7.20
|
||||||
|
license:
|
||||||
|
name: MIT
|
||||||
|
url: 'https://opensource.org/licenses/MIT'
|
||||||
|
gpl-compatible: true
|
||||||
|
cdn:
|
||||||
|
/libraries/c3/: https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.20/
|
||||||
|
css:
|
||||||
|
theme:
|
||||||
|
/libraries/c3/c3.min.css: { }
|
||||||
|
js:
|
||||||
|
/libraries/c3/c3.min.js: { }
|
||||||
|
dependencies:
|
||||||
|
- charts_c3/charts_c3
|
||||||
|
- charts_c3/d3
|
||||||
17
web/modules/charts/modules/charts_c3/charts_c3.module
Normal file
17
web/modules/charts/modules/charts_c3/charts_c3.module
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Implement module related hooks for the charts_c3 module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_charts_version3_to_new_settings_structure_alter().
|
||||||
|
*/
|
||||||
|
function charts_c3_charts_version3_to_new_settings_structure_alter(array &$new_settings, string $for) {
|
||||||
|
$config_factory = \Drupal::configFactory();
|
||||||
|
$c3_config = $config_factory->getEditable('charts_c3.settings');
|
||||||
|
if ($c3_config) {
|
||||||
|
$c3_config->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
49
web/modules/charts/modules/charts_c3/composer.json
Executable file
49
web/modules/charts/modules/charts_c3/composer.json
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "drupal/charts_c3",
|
||||||
|
"description": "Charts module integration with C3 Charts.",
|
||||||
|
"type": "drupal-module",
|
||||||
|
"homepage": "http://drupal.org/project/charts",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://www.drupal.org/project/issues/charts"
|
||||||
|
},
|
||||||
|
"license": "GPL-2.0+",
|
||||||
|
"require": {
|
||||||
|
"c3js/c3": "0.7.20",
|
||||||
|
"d3/d3": "4.9.1"
|
||||||
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "c3js/c3",
|
||||||
|
"version": "v0.7.20",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "c3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://github.com/c3js/c3/archive/v0.7.20.zip",
|
||||||
|
"type": "zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "d3/d3",
|
||||||
|
"version": "v4.9.1",
|
||||||
|
"type": "drupal-library",
|
||||||
|
"extra": {
|
||||||
|
"installer-name": "d3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"url": "https://github.com/d3/d3/archive/v4.9.1.zip",
|
||||||
|
"type": "zip"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/installers": "^1.0 || ^2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
web/modules/charts/modules/charts_c3/js/charts_c3.js
Executable file
21
web/modules/charts/modules/charts_c3/js/charts_c3.js
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* JavaScript's integration between C3 and Drupal.
|
||||||
|
*/
|
||||||
|
(function (Drupal, once) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Drupal.behaviors.chartsC3 = {
|
||||||
|
attach: function (context, settings) {
|
||||||
|
const contents = new Drupal.Charts.Contents();
|
||||||
|
once('charts-c3', '.charts-c3', context).forEach(function (element) {
|
||||||
|
const config = contents.getData(element.id);
|
||||||
|
c3.generate(config);
|
||||||
|
if (element.nextElementSibling && element.nextElementSibling.hasAttribute('data-charts-debug-container')) {
|
||||||
|
element.nextElementSibling.querySelector('code').innerText = JSON.stringify(config, null, ' ');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}(Drupal, once));
|
||||||
454
web/modules/charts/modules/charts_c3/src/Plugin/chart/Library/C3.php
Executable file
454
web/modules/charts/modules/charts_c3/src/Plugin/chart/Library/C3.php
Executable file
@@ -0,0 +1,454 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\charts_c3\Plugin\chart\Library;
|
||||||
|
|
||||||
|
use Drupal\charts\Plugin\chart\Library\ChartBase;
|
||||||
|
use Drupal\Component\Utility\Html;
|
||||||
|
use Drupal\Component\Utility\NestedArray;
|
||||||
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||||
|
use Drupal\Core\Render\Element;
|
||||||
|
use Drupal\Core\Render\ElementInfoManagerInterface;
|
||||||
|
use Drupal\Core\Url;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a concrete class for a Chart.
|
||||||
|
*
|
||||||
|
* @Chart(
|
||||||
|
* id = "c3",
|
||||||
|
* name = @Translation("C3"),
|
||||||
|
* types = {
|
||||||
|
* "area",
|
||||||
|
* "bar",
|
||||||
|
* "bubble",
|
||||||
|
* "column",
|
||||||
|
* "donut",
|
||||||
|
* "gauge",
|
||||||
|
* "line",
|
||||||
|
* "pie",
|
||||||
|
* "scatter",
|
||||||
|
* "spline",
|
||||||
|
* },
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class C3 extends ChartBase implements ContainerFactoryPluginInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The element info manager.
|
||||||
|
*
|
||||||
|
* @var \Drupal\Core\Render\ElementInfoManagerInterface
|
||||||
|
*/
|
||||||
|
protected $elementInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a \Drupal\views\Plugin\Block\ViewsBlockBase object.
|
||||||
|
*
|
||||||
|
* @param array $configuration
|
||||||
|
* A configuration array containing information about the plugin instance.
|
||||||
|
* @param string $plugin_id
|
||||||
|
* The plugin_id for the plugin instance.
|
||||||
|
* @param mixed $plugin_definition
|
||||||
|
* The plugin implementation definition.
|
||||||
|
* @param \Drupal\Core\Render\ElementInfoManagerInterface $element_info
|
||||||
|
* The element info manager.
|
||||||
|
*/
|
||||||
|
public function __construct(array $configuration, $plugin_id, $plugin_definition, ElementInfoManagerInterface $element_info) {
|
||||||
|
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||||
|
$this->elementInfo = $element_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||||
|
return new static(
|
||||||
|
$configuration,
|
||||||
|
$plugin_id,
|
||||||
|
$plugin_definition,
|
||||||
|
$container->get('element_info')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||||
|
$form = parent::buildConfigurationForm($form, $form_state);
|
||||||
|
$form['intro_text'] = [
|
||||||
|
'#markup' => $this->t('<p>This is a placeholder for C3.js-specific library options. If you would like to help build this out, please work from <a href="@issue_link">this issue</a>.</p>', [
|
||||||
|
'@issue_link' => Url::fromUri('https://www.drupal.org/project/charts/issues/3046982')->toString(),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function preRender(array $element) {
|
||||||
|
// Populate chart settings.
|
||||||
|
$chart_definition = [];
|
||||||
|
|
||||||
|
$chart_definition = $this->populateOptions($element, $chart_definition);
|
||||||
|
$chart_definition = $this->populateData($element, $chart_definition);
|
||||||
|
$chart_definition = $this->populateAxes($element, $chart_definition);
|
||||||
|
|
||||||
|
if (!empty($element['#height']) || !empty($element['#width'])) {
|
||||||
|
$element['#attributes']['style'] = 'height:' . $element['#height'] . $element['#height_units'] . ';width:' . $element['#width'] . $element['#width_units'] . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($element['#id'])) {
|
||||||
|
$element['#id'] = Html::getUniqueId('chart-c3');
|
||||||
|
}
|
||||||
|
$chart_definition['bindto'] = '#' . $element['#id'];
|
||||||
|
|
||||||
|
$element['#attached']['library'][] = 'charts_c3/c3';
|
||||||
|
$element['#attributes']['class'][] = 'charts-c3';
|
||||||
|
$element['#chart_definition'] = $chart_definition;
|
||||||
|
|
||||||
|
return $element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chart type.
|
||||||
|
*
|
||||||
|
* @param string $chart_type
|
||||||
|
* The chart type.
|
||||||
|
* @param bool $is_polar
|
||||||
|
* Whether polar is checked.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* Return the type.
|
||||||
|
*/
|
||||||
|
protected function getType($chart_type, $is_polar = FALSE) {
|
||||||
|
// If Polar is checked, then convert to Radar chart type.
|
||||||
|
if ($is_polar) {
|
||||||
|
$type = 'radar';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$type = $chart_type == 'column' ? 'bar' : $chart_type;
|
||||||
|
}
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get options by type.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* The chart type.
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return options.
|
||||||
|
*/
|
||||||
|
protected function getOptionsByType($type, array $element) {
|
||||||
|
$options = $this->getOptionsByCustomProperty($element, $type);
|
||||||
|
if ($type === 'bar') {
|
||||||
|
$options['width'] = $element['#width'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get options by custom property.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param string $type
|
||||||
|
* The chart type.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return options.
|
||||||
|
*/
|
||||||
|
protected function getOptionsByCustomProperty(array $element, $type) {
|
||||||
|
$options = [];
|
||||||
|
$properties = Element::properties($element);
|
||||||
|
// Remove properties which are not related to this chart type.
|
||||||
|
$properties = array_filter($properties, function ($property) use ($type) {
|
||||||
|
$query = '#chart_' . $type . '_';
|
||||||
|
return substr($property, 0, strlen($query)) === $query;
|
||||||
|
});
|
||||||
|
foreach ($properties as $property) {
|
||||||
|
$query = '#chart_' . $type . '_';
|
||||||
|
$option_key = substr($property, strlen($query), strlen($property));
|
||||||
|
$options[$option_key] = $element[$property];
|
||||||
|
}
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate options.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the chart definition.
|
||||||
|
*/
|
||||||
|
private function populateOptions(array $element, array $chart_definition) {
|
||||||
|
$type = $this->getType($element['#chart_type']);
|
||||||
|
$title = $element['#title'] ?? '';
|
||||||
|
if (!empty($element['#subtitle'])) {
|
||||||
|
$title .= ': ' . $element['#subtitle'];
|
||||||
|
}
|
||||||
|
$chart_definition['title']['text'] = $title;
|
||||||
|
$chart_definition['legend']['show'] = !empty($element['#legend_position']);
|
||||||
|
if (!in_array($type, ['scatter', 'bubble'])) {
|
||||||
|
$chart_definition['axis']['x']['type'] = 'category';
|
||||||
|
}
|
||||||
|
$chart_definition['data']['labels'] = (bool) $element['#data_labels'];
|
||||||
|
|
||||||
|
if ($type === 'pie' || $type === 'donut') {
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif ($type === 'gauge') {
|
||||||
|
$chart_definition['gauge']['min'] = $element['#gauge']['min'];
|
||||||
|
$chart_definition['gauge']['max'] = $element['#gauge']['max'];
|
||||||
|
$chart_definition['color']['pattern'] = [
|
||||||
|
'red',
|
||||||
|
'yellow',
|
||||||
|
'green',
|
||||||
|
];
|
||||||
|
$chart_definition['color']['threshold']['values'] = [
|
||||||
|
$element['#gauge']['red_from'],
|
||||||
|
$element['#gauge']['yellow_from'],
|
||||||
|
$element['#gauge']['green_from'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
elseif ($type === 'line' || $type === 'spline') {
|
||||||
|
$chart_definition['point']['show'] = !empty($element['#data_markers']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* Billboard does not use bar, so column must be used. Since 'column'
|
||||||
|
* is changed
|
||||||
|
* to 'bar' in getType(), we need to use the value from the element.
|
||||||
|
*/
|
||||||
|
if ($element['#chart_type'] === 'bar') {
|
||||||
|
$chart_definition['axis']['rotated'] = TRUE;
|
||||||
|
}
|
||||||
|
elseif ($element['#chart_type'] === 'column') {
|
||||||
|
$type = 'bar';
|
||||||
|
$chart_definition['axis']['rotated'] = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$chart_definition['data']['type'] = $type;
|
||||||
|
// Merge in chart raw options.
|
||||||
|
if (!empty($element['#raw_options'])) {
|
||||||
|
$chart_definition = NestedArray::mergeDeepArray([
|
||||||
|
$chart_definition,
|
||||||
|
$element['#raw_options'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chart_definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate axes.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return chart definition.
|
||||||
|
*/
|
||||||
|
private function populateAxes(array $element, array $chart_definition) {
|
||||||
|
$children = Element::children($element);
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$type = $element[$child]['#type'];
|
||||||
|
if ($type === 'chart_xaxis') {
|
||||||
|
$chart_definition['axis']['x']['label'] = $element[$child]['#title'] ?? '';
|
||||||
|
$chart_type = $this->getType($element['#chart_type']);
|
||||||
|
$categories = $this->stripLabelTags($element[$child]['#labels']);
|
||||||
|
if (!in_array($chart_type, ['pie', 'donut'])) {
|
||||||
|
if ($chart_type === 'scatter' || $chart_type === 'bubble') {
|
||||||
|
// Scatter is not supported: https://github.com/c3js/c3/issues/1902
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$chart_definition['data']['columns'][] = ['x'];
|
||||||
|
$chart_definition['data']['x'] = 'x';
|
||||||
|
$categories_keys = array_keys($chart_definition['data']['columns']);
|
||||||
|
$categories_key = end($categories_keys);
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$chart_definition['data']['columns'][$categories_key][] = $category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$chart_definition['data']['columns'] = array_map(NULL, $categories, $chart_definition['data']['columns']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($type === 'chart_yaxis') {
|
||||||
|
if (!empty($element[$child]['#opposite']) && $element[$child]['#opposite'] === TRUE) {
|
||||||
|
$chart_definition['axis']['y2']['show'] = TRUE;
|
||||||
|
$this->setLabelMinMax($chart_definition, 'y2', $element[$child]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->setLabelMinMax($chart_definition, 'y', $element[$child]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chart_definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the label, min, and max.
|
||||||
|
*
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
* @param string $axis
|
||||||
|
* The axis.
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
*/
|
||||||
|
private function setLabelMinMax(array &$chart_definition, string $axis, array $element): void {
|
||||||
|
$chart_definition['axis'][$axis]['label'] = $element['#title'] ?? '';
|
||||||
|
if (!empty($element['#min'])) {
|
||||||
|
$chart_definition['axis'][$axis]['min'] = $element['#min'];
|
||||||
|
}
|
||||||
|
if (!empty($element['#max'])) {
|
||||||
|
$chart_definition['axis'][$axis]['max'] = $element['#max'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate data.
|
||||||
|
*
|
||||||
|
* @param array $element
|
||||||
|
* The element.
|
||||||
|
* @param array $chart_definition
|
||||||
|
* The chart definition.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the chart definition.
|
||||||
|
*/
|
||||||
|
private function populateData(array &$element, array $chart_definition) {
|
||||||
|
$type = $this->getType($element['#chart_type']);
|
||||||
|
$types = [];
|
||||||
|
$children = Element::children($element);
|
||||||
|
$y_axes = [];
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$element_type = $element[$child]['#type'];
|
||||||
|
if ($element_type === 'chart_yaxis') {
|
||||||
|
$y_axes[] = $child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data_elements = array_filter($children, function ($child) use ($element) {
|
||||||
|
return $element[$child]['#type'] === 'chart_data';
|
||||||
|
});
|
||||||
|
|
||||||
|
$columns = $chart_definition['data']['columns'] ?? [];
|
||||||
|
$column_keys = array_keys($columns);
|
||||||
|
$columns_key_start = $columns ? end($column_keys) + 1 : 0;
|
||||||
|
foreach ($data_elements as $key) {
|
||||||
|
$child_element = $element[$key];
|
||||||
|
// Make sure defaults are loaded.
|
||||||
|
if (empty($child_element['#defaults_loaded'])) {
|
||||||
|
$child_element += $this->elementInfo->getInfo($child_element['#type']);
|
||||||
|
}
|
||||||
|
if ($child_element['#color'] && $type !== 'gauge') {
|
||||||
|
$chart_definition['color']['pattern'][] = $child_element['#color'];
|
||||||
|
}
|
||||||
|
if (!in_array($type, ['pie', 'donut'])) {
|
||||||
|
$series_title = isset($child_element['#title']) ? strip_tags($child_element['#title']) : '';
|
||||||
|
$types[$series_title] = $child_element['#chart_type'] ? $this->getType($child_element['#chart_type']) : $type;
|
||||||
|
if (!in_array($type, ['scatter', 'bubble'])) {
|
||||||
|
$columns[$columns_key_start][] = $series_title;
|
||||||
|
foreach ($child_element['#data'] as $datum) {
|
||||||
|
if (gettype($datum) === 'array') {
|
||||||
|
if ($type === 'gauge') {
|
||||||
|
array_shift($datum);
|
||||||
|
}
|
||||||
|
$columns[$columns_key_start][] = array_map(function ($item) {
|
||||||
|
return isset($item) ? strip_tags($item) : NULL;
|
||||||
|
}, $datum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$columns[$columns_key_start][] = isset($datum) ? strip_tags($datum) : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$row = [];
|
||||||
|
$row[$series_title][0] = $series_title;
|
||||||
|
$row[$series_title . '_x'][0] = $series_title . '_x';
|
||||||
|
foreach ($child_element['#data'] as $datum) {
|
||||||
|
$row[$series_title][] = $datum[0];
|
||||||
|
$row[$series_title . '_x'][] = $datum[1];
|
||||||
|
}
|
||||||
|
$chart_definition['data']['xs'][$series_title] = $series_title . '_x';
|
||||||
|
foreach ($row as $value) {
|
||||||
|
$columns[] = $value;
|
||||||
|
}
|
||||||
|
$columns = array_values($columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach ($child_element['#data'] as $datum_index => $datum) {
|
||||||
|
if (!empty($datum['color'])) {
|
||||||
|
$chart_definition['color']['pattern'][$datum_index] = $datum['color'];
|
||||||
|
unset($datum['color']);
|
||||||
|
$datum = array_values($datum);
|
||||||
|
}
|
||||||
|
$columns[] = $datum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add colors for each segment.
|
||||||
|
foreach ($child_element['#grouping_colors'] ?? [] as $key => $colors_array) {
|
||||||
|
$color = reset($colors_array);
|
||||||
|
$chart_definition['color']['pattern'][$key] = $color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns_key_start++;
|
||||||
|
}
|
||||||
|
if ($element['#stacking']) {
|
||||||
|
$chart_definition['data']['groups'] = [array_keys($types)];
|
||||||
|
}
|
||||||
|
$chart_definition['data']['types'] = $types;
|
||||||
|
$chart_definition['data']['columns'] = $columns;
|
||||||
|
|
||||||
|
if (count($y_axes) >= 2) {
|
||||||
|
foreach ($columns as $index => $column) {
|
||||||
|
if ($index <= 1) {
|
||||||
|
$axis = ($index + 1) === 2 ? 2 : '';
|
||||||
|
$chart_definition['data']['axes'][$column[0]] = 'y' . $axis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $chart_definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip tags from each item in an array.
|
||||||
|
*
|
||||||
|
* @param array $items
|
||||||
|
* The array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Return the cleaned array.
|
||||||
|
*/
|
||||||
|
private function stripLabelTags(array $items): array {
|
||||||
|
if (empty($items)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$categories = [];
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$categories[] = isset($item) ? strip_tags($item) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
158
web/modules/charts/modules/charts_chartjs/README.md
Executable file
158
web/modules/charts/modules/charts_chartjs/README.md
Executable file
@@ -0,0 +1,158 @@
|
|||||||
|
#Installation Using Composer (recommended)
|
||||||
|
|
||||||
|
If you use Composer to manage dependencies, edit your site's "composer.json"
|
||||||
|
file as follows.
|
||||||
|
|
||||||
|
1. Add the asset-packagist composer repository to "composer.json".
|
||||||
|
This allows installing packages (like Chart.js) that are published on NPM.
|
||||||
|
|
||||||
|
"asset-packagist": {
|
||||||
|
"type": "composer",
|
||||||
|
"url": "https://asset-packagist.org"
|
||||||
|
},
|
||||||
|
|
||||||
|
You may need to add it in your composer.json file like this (second item in
|
||||||
|
the array):
|
||||||
|
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "composer",
|
||||||
|
"url": "https://packages.drupal.org/8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "composer",
|
||||||
|
"url": "https://asset-packagist.org"
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
2. Run the following command to ensure that you have the
|
||||||
|
"oomphinc/composer-installers-extender" package installed. This package
|
||||||
|
facilitates the installation of any package into directories other than the
|
||||||
|
default "/vendor" (e.g. "/libraries") using Composer.
|
||||||
|
|
||||||
|
composer require --prefer-dist oomphinc/composer-installers-extender
|
||||||
|
|
||||||
|
3. Configure composer to install the Chart.js dependencies into "/libraries"
|
||||||
|
by adding the following "installer-types" and "installer-paths" to the "extra"
|
||||||
|
section of "composer.json". If you are not using the "web" directory, then
|
||||||
|
remove "web/" from the lines below:
|
||||||
|
|
||||||
|
"extra": {
|
||||||
|
"installer-types": ["npm-asset"],
|
||||||
|
"installer-paths": {
|
||||||
|
"web/libraries/chart.js": ["npm-asset/chart.js"],
|
||||||
|
"web/libraries/chartjs-adapter-date-fns": [
|
||||||
|
"npm-asset/chartjs-adapter-date-fns"
|
||||||
|
],
|
||||||
|
"web/libraries/chartjs-plugin-datalabels": [
|
||||||
|
"npm-asset/chartjs-plugin-datalabels"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTE: If this isn't working, try instead adding:
|
||||||
|
"extra": {
|
||||||
|
"installer-types": ["npm-asset"],
|
||||||
|
"installer-paths": {
|
||||||
|
...
|
||||||
|
"web/libraries/{$name}": ["type:drupal-library", "vendor:npm-asset"]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
4. This and the following step is optional but recommended. The reason for
|
||||||
|
them is that when installing the Chart.js package with Composer,
|
||||||
|
additional files are added into the library directory. These files are not
|
||||||
|
necessary and can be potentially harmful to your site, so it's best to remove
|
||||||
|
them. So: create a new directory in your project root called "scripts".
|
||||||
|
|
||||||
|
5. Inside that directory, create a new file called "clean-chartjs.sh" and
|
||||||
|
paste the following into it:
|
||||||
|
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
declare -a directories=(
|
||||||
|
"web/libraries/chart.js/auto"
|
||||||
|
"web/libraries/chart.js/helpers"
|
||||||
|
"web/libraries/chart.js/types"
|
||||||
|
"web/libraries/chart.js/dist/chunks"
|
||||||
|
"web/libraries/chart.js/dist/docs"
|
||||||
|
"web/libraries/chart.js/dist/controllers"
|
||||||
|
"web/libraries/chart.js/dist/core"
|
||||||
|
"web/libraries/chart.js/dist/elements"
|
||||||
|
"web/libraries/chart.js/dist/helpers"
|
||||||
|
"web/libraries/chart.js/dist/platform"
|
||||||
|
"web/libraries/chart.js/dist/plugins"
|
||||||
|
"web/libraries/chart.js/dist/scales"
|
||||||
|
"web/libraries/chart.js/dist/types"
|
||||||
|
"web/libraries/chartjs-plugin-datalabels/types"
|
||||||
|
)
|
||||||
|
counter=0
|
||||||
|
echo "Deleting unneeded directories inside web/libraries/chartjs"
|
||||||
|
for directory in "${directories[@]}"
|
||||||
|
do
|
||||||
|
if [ -d $directory ]; then
|
||||||
|
echo "Deleting $directory"
|
||||||
|
rm -rf $directory
|
||||||
|
counter=$((counter+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$counter folders were deleted"
|
||||||
|
declare -a files=(
|
||||||
|
"web/libraries/chart.js/README.md"
|
||||||
|
"web/libraries/chart.js/LICENSE.md"
|
||||||
|
"web/libraries/chart.js/package.json"
|
||||||
|
"web/libraries/chart.js/dist/helpers.esm.js"
|
||||||
|
"web/libraries/chart.js/dist/helpers.mjs"
|
||||||
|
"web/libraries/chart.js/dist/chart.mjs"
|
||||||
|
"web/libraries/chart.js/dist/chart.esm.js"
|
||||||
|
"web/libraries/chart.js/dist/chart.cjs"
|
||||||
|
"web/libraries/chart.js/dist/chart.cjs.map"
|
||||||
|
"web/libraries/chart.js/dist/helpers.js"
|
||||||
|
"web/libraries/chart.js/dist/helpers.js.map"
|
||||||
|
"web/libraries/chart.js/dist/helpers.cjs"
|
||||||
|
"web/libraries/chart.js/dist/helpers.cjs.map"
|
||||||
|
"web/libraries/chart.js/dist/index.d.ts"
|
||||||
|
"web/libraries/chart.js/dist/index.umd.d.ts"
|
||||||
|
"web/libraries/chart.js/dist/types.d.ts"
|
||||||
|
"web/libraries/chartjs-adapter-date-fns/README.md"
|
||||||
|
"web/libraries/chartjs-adapter-date-fns/LICENSE.md"
|
||||||
|
"web/libraries/chartjs-adapter-date-fns/package.json"
|
||||||
|
"web/libraries/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.esm.js"
|
||||||
|
"web/libraries/chartjs-plugin-datalabels/README.md"
|
||||||
|
"web/libraries/chartjs-plugin-datalabels/LICENSE.md"
|
||||||
|
"web/libraries/chartjs-plugin-datalabels/package.json"
|
||||||
|
"web/libraries/chartjs-plugin-datalabels/bower.json"
|
||||||
|
)
|
||||||
|
counter=0
|
||||||
|
echo "Deleting unneeded files inside web/libraries/chartjs"
|
||||||
|
for file in "${files[@]}"
|
||||||
|
do
|
||||||
|
if [[ -f $file ]]; then
|
||||||
|
echo "Deleting $file"
|
||||||
|
rm $file
|
||||||
|
counter=$((counter+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$counter files were deleted"
|
||||||
|
|
||||||
|
6. Add a "scripts" entry to your "composer.json" file as shown below. If
|
||||||
|
"scripts" already exists, you will need to do a little more to incorporate
|
||||||
|
the code below.
|
||||||
|
|
||||||
|
"scripts": {
|
||||||
|
"clean-chartjs": "chmod +x scripts/clean-chartjs.sh &&
|
||||||
|
./scripts/clean-chartjs.sh",
|
||||||
|
"post-install-cmd": [
|
||||||
|
"@clean-chartjs"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@clean-chartjs"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
7. Run the following command; you should find that new directories have been
|
||||||
|
created under "/libraries".
|
||||||
|
|
||||||
|
composer require --prefer-dist npm-asset/chart.js:^4.4
|
||||||
|
npm-asset/chartjs-adapter-date-fns:^3.0
|
||||||
|
npm-asset/chartjs-plugin-datalabels:^2.0
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
polarArea:
|
||||||
|
label: 'Polar Area'
|
||||||
|
axis: 'y_only'
|
||||||
|
axis_inverted: false
|
||||||
|
stacking: false
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
name: 'Chart.js Charts'
|
||||||
|
type: module
|
||||||
|
description: 'Charts module integration with Chart.js.'
|
||||||
|
package: Charts
|
||||||
|
core_version_requirement: ^10.3 || ^11
|
||||||
|
dependencies:
|
||||||
|
- 'charts:charts'
|
||||||
|
|
||||||
|
# Information added by Drupal.org packaging script on 2024-12-02
|
||||||
|
version: '5.1.1'
|
||||||
|
project: 'charts'
|
||||||
|
datestamp: 1733170633
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Installation and uninstallation functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_requirements().
|
||||||
|
*/
|
||||||
|
function charts_chartjs_requirements($phase) {
|
||||||
|
$requirements = [];
|
||||||
|
|
||||||
|
switch ($phase) {
|
||||||
|
case 'runtime':
|
||||||
|
$library_path = charts_chartjs_find_library();
|
||||||
|
$config = \Drupal::config('charts.settings');
|
||||||
|
$cdn = $config->get('advanced.requirements.cdn') ?? FALSE;
|
||||||
|
|
||||||
|
if (!$library_path) {
|
||||||
|
if ($cdn) {
|
||||||
|
$requirements['charts_chartjs_js'] = [
|
||||||
|
'title' => t('Chart.js Library'),
|
||||||
|
'value' => t('Available through a CDN'),
|
||||||
|
'severity' => REQUIREMENT_WARNING,
|
||||||
|
'description' => t('You are using the Chart.js library via a content delivery network. It is generally considered better practice to install the library files locally. Please see the README file inside charts_chartjs for instructions to install the library.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$requirements['charts_chartjs_js'] = [
|
||||||
|
'title' => t('Chart.js Library'),
|
||||||
|
'value' => t('Not Installed'),
|
||||||
|
'severity' => REQUIREMENT_ERROR,
|
||||||
|
'description' => t('You are missing the Chart.js library in your Drupal installation directory and you have opted not to use a CDN. Please either enable use of the CDN in the Chart Settings under the Advanced tab or see the README file inside charts_chartjs for instructions to install the library.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If the library directory contains "auto", provide a warning.
|
||||||
|
if (file_exists($library_path . '/auto')) {
|
||||||
|
$requirements['charts_chartjs_js'] = [
|
||||||
|
'title' => t('Chart.js Library'),
|
||||||
|
'value' => t('Installed'),
|
||||||
|
'severity' => REQUIREMENT_WARNING,
|
||||||
|
'description' => t('You have installed the Chart.js library in your Drupal installation directory, but it contains additional files that are not required and may be harmful. Please delete everything except the files listed in charts_chartjs.libraries.yml. We have included a suggested post-install/post-update script in the README file.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$requirements['charts_chartjs_js'] = [
|
||||||
|
'title' => t('Chart.js Library'),
|
||||||
|
'value' => t('Installed'),
|
||||||
|
'severity' => REQUIREMENT_OK,
|
||||||
|
'description' => t('You have installed the Chart.js library in your Drupal installation directory.'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the location of the Chart.js library.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* The location of the library, or FALSE if the library isn't installed.
|
||||||
|
*/
|
||||||
|
function charts_chartjs_find_library() {
|
||||||
|
// The following logic is taken from libraries_get_libraries()
|
||||||
|
$searchdir = [];
|
||||||
|
|
||||||
|
// Similar to 'modules' and 'themes' directories inside an installation
|
||||||
|
// profile, installation profiles may want to place libraries into a
|
||||||
|
// 'libraries' directory.
|
||||||
|
$searchdir[] = 'profiles/' . \Drupal::installProfile() . '/libraries';
|
||||||
|
|
||||||
|
// Always search libraries.
|
||||||
|
$searchdir[] = 'libraries';
|
||||||
|
|
||||||
|
// Also search sites/<domain>/*.
|
||||||
|
$container = \Drupal::getContainer();
|
||||||
|
$site_path = $container->getParameter('site.path');
|
||||||
|
$site_path = explode('/', $site_path);
|
||||||
|
$site_name = $site_path[1];
|
||||||
|
$searchdir[] = $site_name . '/libraries';
|
||||||
|
|
||||||
|
foreach ($searchdir as $dir) {
|
||||||
|
if (file_exists($dir . '/chart.js/dist/chart.js') || file_exists($dir . '/chart.js/dist/chart.umd.js')) {
|
||||||
|
return $dir . '/chartjs';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
26
web/modules/charts/modules/charts_chartjs/charts_chartjs.libraries.yml
Executable file
26
web/modules/charts/modules/charts_chartjs/charts_chartjs.libraries.yml
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
charts_chartjs:
|
||||||
|
remote: 'https://github.com/chartjs/Chart.js'
|
||||||
|
version: VERSION
|
||||||
|
license:
|
||||||
|
name: 'Apache 2.0'
|
||||||
|
url: 'https://www.apache.org/licenses/LICENSE-2.0'
|
||||||
|
gpl-compatible: false
|
||||||
|
# @todo
|
||||||
|
cdn:
|
||||||
|
/libraries/chart.js/: https://unpkg.com/chart.js@4.4.0/
|
||||||
|
/libraries/chartjs-adapter-date-fns/: https://unpkg.com/chartjs-adapter-date-fns@3.0.0/
|
||||||
|
/libraries/chartjs-plugin-datalabels/: https://unpkg.com/chartjs-plugin-datalabels@2.0.0/
|
||||||
|
js:
|
||||||
|
/libraries/chart.js/dist/chart.umd.js: { }
|
||||||
|
/libraries/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.js: { }
|
||||||
|
/libraries/chartjs-plugin-datalabels/dist/chartjs-plugin-datalabels.js: { }
|
||||||
|
dependencies:
|
||||||
|
- core/drupal
|
||||||
|
- core/once
|
||||||
|
chartjs:
|
||||||
|
version: 1.x
|
||||||
|
js:
|
||||||
|
js/charts_chartjs.js: { weight: -1 }
|
||||||
|
dependencies:
|
||||||
|
- charts/global
|
||||||
|
- charts_chartjs/charts_chartjs
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Implement module related hooks for the charts_chartjs module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_charts_version3_to_new_settings_structure_alter().
|
||||||
|
*/
|
||||||
|
function charts_chartjs_charts_version3_to_new_settings_structure_alter(array &$new_settings, string $for) {
|
||||||
|
$config_factory = \Drupal::configFactory();
|
||||||
|
$is_config = $for === 'config';
|
||||||
|
$chartjs_config = $is_config ? $config_factory->getEditable('charts_chartjs.settings') : NULL;
|
||||||
|
if (!$is_config || !$chartjs_config || empty($new_settings['library']) || $new_settings['library'] !== 'chartjs') {
|
||||||
|
if ($chartjs_config) {
|
||||||
|
$chartjs_config->delete();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_settings['library_config'] = [
|
||||||
|
'xaxis' => [
|
||||||
|
'autoskip' => TRUE,
|
||||||
|
'horizontal_axis_title_align' => 'start',
|
||||||
|
],
|
||||||
|
'yaxis' => [
|
||||||
|
'vertical_axis_title_align' => 'start',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$chartjs_config->delete();
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user