Skip to content
Snippets Groups Projects
Commit 10552c31 authored by Kevin Hill's avatar Kevin Hill
Browse files

Squashed 'lavajs/' content from commit 8d3156c

git-subtree-dir: lavajs
git-subtree-split: 8d3156ca7b984ab501f7e015b87cb3943224e159
parents
No related branches found
No related tags found
No related merge requests found
{
"presets": [
"es2015"
]
}
.idea/
node_modules/
renders/*.png
{
// Settings
"passfail" : false, // Stop on first error.
"maxerr" : 100, // Maximum error before stopping.
"esversion" : 6,
// Predefined globals whom JSHint will ignore.
"browser" : true, // Standard browser globals e.g. `window`, `document`.
"predef" : [ // Custom globals.
"google"
],
// Development.
"debug" : false, // Allow debugger statements e.g. browser breakpoints.
"devel" : true, // Allow developments statements e.g. `console.log();`.
// ECMAScript 5.
"es5" : false, // Allow ECMAScript 5 syntax.
"strict" : false, // Require `use strict` pragma in every file.
"globalstrict" : false, // Allow global "use strict" (also enables 'strict').
// The Good Parts.
"asi" : true, // Tolerate Automatic Semicolon Insertion (no semicolons).
"laxbreak" : true, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
"bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.).
"boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
"curly" : true, // Require {} for every new block or scope.
"eqeqeq" : true, // Require triple equals i.e. `===`.
"eqnull" : false, // Tolerate use of `== null`.
"evil" : false, // Tolerate use of `eval`.
"expr" : false, // Tolerate `ExpressionStatement` as Programs.
"forin" : false, // Tolerate `for in` loops without `hasOwnPrototype`.
"immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
"latedef" : true, // Prohipit variable use before definition.
"loopfunc" : false, // Allow functions to be defined within loops.
"noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`.
"regexp" : true, // Prohibit `.` and `[^...]` in regular expressions.
"regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`.
"scripturl" : true, // Tolerate script-targeted URLs.
"shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`.
"supernew" : false, // Tolerate `new function () { ... };` and `new Object;`.
"undef" : true, // Require all non-global variables be declared before they are used.
// Personal styling preferences.
"newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`.
"noempty" : true, // Prohibit use of empty blocks.
"nonew" : true, // Prohibit use of constructors for side-effects.
"nomen" : true, // Prohibit use of initial or trailing underbars in names.
"onevar" : false, // Allow only one `var` statement per function.
"plusplus" : false, // Prohibit use of `++` & `--`.
"sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
"trailing" : true, // Prohibit trailing whitespaces.
"white" : false, // Check against strict whitespace and indentation rules.
"indent" : 2 // Specify indentation spacing
}
LICENSE 0 → 100644
MIT License
Copyright (c) 2017 lavacharts
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Lava.js
[![Build Status](https://travis-ci.org/lavacharts/lava.js.svg?branch=master)](https://travis-ci.org/lavacharts/lava.js)
Lava.js is the javsacript module that accompanies the [Lavacharts PHP library](https://github.com/kevinkhill/lavacharts)
## New!
As of v4.0, Lava.js can be used independently from Lavacharts if you feel so inclined.
Clone or download the repo and check out the examples folder to see how easy it can be to make charts.
/* jshint undef: true */
/* globals module, require, phantom, window */
"use strict";
var resemble = require('node-resemble-js');
var rendersDir = './javascript/phantomjs/renders/';
var args = process.argv;
var chart = args[2];
resemble(rendersDir + chart + '.png').compareTo(rendersDir + chart + '.png').onComplete(function (data) {
//console.log(data);
if (Number(data.misMatchPercentage) <= 0.01) {
console.log('Pass!');
} else {
console.log('Fail!');
}
});
Source diff could not be displayed: it is too large. Options to address this: view the blob.
<!doctype html>
<html>
<head>
<title>Lava.js | Events</title>
<script type="text/javascript" src="../dist/lava.js"></script>
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<style rel="stylesheet" type="text/css">
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Nunito', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
p {
font-size: larger;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.align-left {
text-align: left;
}
.float {
float: left;
}
.content {
text-align: center;
}
.title {
font-size: 74px;
}
</style>
</head>
<body>
<div class="flex-center position-ref">
<div class="content">
<div class="title">
Lava.js v4.0
</div>
<p>Event integration (click a slice!)</p>
<div>
<div class="align-left float">
<pre><code>
var chartJson = {
label: "Test",
type: "PieChart",
elementId: "my-pie-chart",
datatable: function (data) {
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
['Mushrooms', 3],
['Onions', 1],
['Olives', 1],
['Zucchini', 1],
['Pepperoni', 2]
]);
return data;
},
options: {
title: 'My Daily Activities'
},
};
var chart = lava.store(chartJson);
chart.on('ready', function() {
console.log(this.uuid + ' is ready!');
});
chart.on('select', function (chart, data) {
var selectedItem = chart.getSelection()[0];
if (selectedItem) {
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
});
lava.run();
</code></pre>
</div>
<div class="float" style="width: 400px;">
<pre><code>
&#x3C;div id=&#x22;my-pie-chart&#x22;&#x3E;&#x3C;/div&#x3E;
</code></pre>
<div id="my-pie-chart"></div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var chartJson = {
label: "Test",
type: "PieChart",
elementId: "my-pie-chart",
datatable: function (data) {
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
['Mushrooms', 3],
['Onions', 1],
['Olives', 1],
['Zucchini', 1],
['Pepperoni', 2]
]);
return data;
},
options: {
title: 'My Daily Activities'
},
};
var chart = lava.store(chartJson);
chart.on('ready', function() {
alert(this.uuid + ' is ready!');
});
chart.on('select', function (chart, data) {
var selectedItem = chart.getSelection()[0];
if (selectedItem) {
var topping = data.getValue(selectedItem.row, 0);
alert('The user selected ' + topping);
}
});
lava.run();
</script>
</body>
</html>
<!doctype html>
<html>
<head>
<title>Lava.js | Basic Syntax</title>
<script type="text/javascript" src="../dist/lava.js"></script>
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<style rel="stylesheet" type="text/css">
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Nunito', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
p {
font-size: larger;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.align-left {
text-align: left;
}
.float {
float: left;
}
.content {
text-align: center;
}
.title {
font-size: 74px;
}
</style>
</head>
<body>
<div class="flex-center position-ref">
<div class="content">
<div class="title">
Lava.js v4.0
</div>
<p>The Google Chart API wrapper.</p>
<div>
<div class="align-left float">
<pre><code>
var chartJson = {
label: "Test",
type: "PieChart",
elementId: "my-pie-chart",
datatable: [
['Task', 'Hours per Day'],
['Work', 11],
['Eat', 2],
['Commute', 2],
['Watch TV', 2],
['Sleep', 7]
],
options: {
title: 'My Daily Activities'
},
};
lava.store(chartJson);
lava.run();
</code></pre>
</div>
<div class="float" style="width: 400px;">
<pre><code>
&#x3C;div id=&#x22;my-pie-chart&#x22;&#x3E;&#x3C;/div&#x3E;
</code></pre>
<div id="my-pie-chart"></div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var chartJson = {
label: "Test",
type: "PieChart",
elementId: "my-pie-chart",
datatable: [
['Task', 'Hours per Day'],
['Work', 11],
['Eat', 2],
['Commute', 2],
['Watch TV', 2],
['Sleep', 7]
],
options: {
title: 'My Daily Activities'
},
};
lava.store(chartJson);
lava.run();
</script>
</body>
</html>
import args from 'yargs';
import gulpif from 'gulp-if';
import source from 'vinyl-source-stream';
import notifier from 'node-notifier';
import browserify from 'browserify';
import uglify from 'gulp-uglify';
import babelify from 'babelify';
import watchify from 'watchify';
import streamify from 'gulp-streamify';
import {dest} from 'gulp';
import {log} from 'gulp-util';
import {green, red} from 'chalk';
import {create as createBrowserSync} from 'browser-sync';
const browserSync = createBrowserSync();
let bundler = browserify({
debug: true,
entries: ['./src/lava.entry.js'],
cache: {},
packageCache: {},
transform: [
'browserify-versionify',
['babelify', {presets: ['es2015'] }]
]
});
function rebundle(prod = false) {
return bundler.bundle()
.on('error', err => {
if (err instanceof SyntaxError) {
log(red('Syntax Error'));
log(err.message);
// log(err.filename+":"+err.loc.line);
log(err.codeFrame);
} else {
log(red('Error'), err.message);
}
})
.pipe(source('lava.js'))
.pipe(gulpif(prod, streamify(uglify())))
.pipe(dest('dist'));
}
export default function compile(prod, watch, sync) {
if (prod) {
bundler.transform('stripify');
}
if (watch) {
bundler = watchify(bundler);
if (sync) {
browserSync.init({
proxy: "localhost:" + args.port || 8000
});
}
bundler.on('update', () => {
const msg = 'Lava.js re-bundling...';
log(green(msg));
notifier.notify({
title: 'Browserify',
message: msg
});
rebundle(prod);
});
bundler.on('log', msg => {
log(green(msg));
if (sync) {
browserSync.reload();
}
});
}
return rebundle(prod);
}
import { map } from 'lodash';
import { cwd } from 'process';
import { resolve } from 'path';
import { sync as globSync } from 'glob';
export default function getChartTypes() {
let chartTypes = globSync('*.php', {
cwd: resolve(cwd(), '../src/Charts/'),
nomount: true,
ignore: [
'Chart.php',
'ChartBuilder.php',
'ChartFactory.php',
]
});
return map(chartTypes, chartType => {
return chartType.slice(0, -4);
});
}
import PortFinder from 'portfinder';
import PhpServer from 'gulp-connect-php';
import { cwd } from 'process';
import { resolve } from 'path';
function _createServer(port) {
const base = resolve(cwd(), '../tests/Examples');
const server = new PhpServer();
return new Promise(resolve => {
server.server({
base: base,
port: port,
ini: base + '/php.ini',
router: base + '/renderer.php'
});
resolve(server);
});
}
export default function getPhpServer() {
return PortFinder
.getPortPromise()
.then(_createServer)
.catch(err => {
console.log(err);
});
}
import Nightmare from 'nightmare';
import getPhpServer from './PhpServer';
import { cwd } from 'process';
import { resolve } from 'path';
function _getNightmare(timeout) {
return new Nightmare({
gotoTimeout: timeout,
waitTimeout: timeout,
loadTimeout: timeout,
executionTimeout: timeout
});
}
export default function renderChart(chartType) {
return getPhpServer()
.then(server => {
let chartUrl = 'http://localhost:' + server.port + '/' + chartType;
let renderDir = resolve(cwd(), 'renders');
let chartImg = renderDir + '/' + chartType + '.png';
console.log('Nightmare opening ' + chartUrl);
return _getNightmare(5000)
.viewport(800, 600)
.goto(chartUrl)
.wait(3000)
.screenshot(chartImg)
.end(() => {
console.log('Saved screenshot to ' + chartImg);
server.closeServer();
});
});
}
/* jshint node:true */
import gulp from 'gulp';
import yargs from 'yargs';
import compile from './gulp-functions/Compile';
import renderChart from './gulp-functions/Renderer';
import getChartTypes from './gulp-functions/GetChartTypes';
import {cpus} from 'os'
import {map} from 'bluebird';
import { log } from 'gulp-util';
import { red, green } from 'chalk';
gulp.task('default', ['dev']);
/**
* Lava.js compilation tasks.
*
* The compile method accepts three boolean flags for the following signature:
* compile(prod, watch, sync)
*/
gulp.task('dev', () => { compile(false, false, false) });
gulp.task('prod', () => { compile(true, false, false) });
gulp.task('watch', () => { compile(false, true, false) });
gulp.task('sync', () => { compile(false, true, true) });
/**
* Render a specific chart.
*
* Specify the type as the php class name
*
* Syntax:
* gulp render --type [ AreaChart | LineChart | GeoChart | etc... ]
*/
gulp.task('render', done => {
const chartTypes = getChartTypes();
const args = yargs
.fail(msg => {
throw new Error(msg);
})
.alias('t', 'type')
.describe('t', 'choose the type of chart to render')
.choices('t', chartTypes)
.wrap(70)
.help('help')
.argv;
renderChart(args.t)
.then(() => {
done();
})
.catch(err => {
console.log(err);
});
});
/**
* Render all of the available charts.
*
* The renders will be ran in batches equal to the number of processors.
*
* Syntax:
* gulp renderAll
*/
gulp.task('renderAll', done => {
let batchSize = cpus().length;
console.log('Rendering charts in batches of '+batchSize);
map(getChartTypes(), chartType => {
return renderChart(chartType);
}, {concurrency: batchSize})
.then(() => {
done();
})
.catch(err => {
console.log(err);
});
});
/**
* Get all available chart types
*
* Syntax:
* gulp charts
*/
gulp.task('charts', done => {
console.log('Available charts for rendering:');
console.log(getChartTypes().join(', '));
done();
});
/* jshint node:true */
module.exports = function (config) {
config.set({
frameworks: ['jasmine','sinon'],
files: [
'./node_modules/jasmine-sinon/lib/jasmine-sinon.js',
'./dist/lava.js',
'./tests/lava.spec.js'
],
singleRun: false,
reporters: ['dots'],
port: 9876,
colors: true,
logLevel: config.LOG_ERROR,
autoWatch: true,
browsers: [(process.env.TRAVIS ? 'PhantomJS' : 'Chrome')]
});
};
{
"name": "@lavacharts/lava.js",
"version": "4.0.0",
"description": "Wrapper library for the Google Chart API",
"homepage": "http://lavacharts.com",
"author": "Kevin Hill",
"license": "MIT",
"private": true,
"engines": {
"node": "0.12.*"
},
"dependencies": {
"lodash": "^4.17.4"
},
"devDependencies": {
"@angular/core": "^4.2.4",
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-register": "^6.24.1",
"babelify": "^7.3.0",
"bluebird": "^3.5.0",
"browser-sync": "^2.18.12",
"browserify": "^14.4.0",
"browserify-replace": "^0.9.0",
"browserify-versionify": "^1.0.6",
"glob": "^7.1.2",
"gulp": "^3.9.1",
"gulp-babel": "^7.0.0",
"gulp-bump": "^0.3.0",
"gulp-connect-php": "^1.0.1",
"gulp-ext": "^1.0.0",
"gulp-if": "^2.0.0",
"gulp-jshint": "^1.10.0",
"gulp-notify": "^3.0.0",
"gulp-rename": "^1.2.2",
"gulp-replace": "^0.6.1",
"gulp-spawn": "^0.3.0",
"gulp-streamify": "^1.0.2",
"gulp-tap": "^1.0.1",
"gulp-uglify": "^1.5.3",
"gulp-util": "^3.0.8",
"jasmine-core": "^2.6.4",
"jasmine-sinon": "^0.4.0",
"jsdoc": "^3.4.0",
"jshint-stylish": "^2.1.0",
"karma": "^0.13.0",
"karma-jasmine": "^0.3.5",
"karma-sinon": "^1.0.4",
"nightmare": "^2.10.0",
"node-notifier": "^5.1.2",
"node-resemble-js": "^0.2.0",
"portfinder": "^1.0.13",
"rxjs": "^5.1.0",
"sinon": "^1.17.3",
"stripify": "^4.0.0",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.7.0",
"yargs": "^3.6.0",
"zone.js": "^0.8.12"
},
"repository": {
"type": "git",
"url": "https://github.com/kevinkhill/lavacharts.git"
},
"bugs": {
"url": "https://github.com/kevinkhill/lavacharts/issues"
},
"scripts": {
"gulp": "./node_modules/.bin/gulp",
"test": "./node_modules/.bin/karma start --singleRun",
"jsdoc": "./node_modules/.bin/jsdoc -d build/jsdoc --package package.json javascript/src/lava/Lava.js"
}
}
import { Injectable } from '@angular/core';
function getWindow() {
return window;
}
@Injectable()
export class LavaJsService {
private _window: any;
constructor() {
this._window = getWindow();
console.log('[lava.js] Angular service provider loaded.');
}
/**
* Returns the Lava.js instance attached to the window.
*
* @return {LavaJs}
*/
getInstance() {
return this._window.lava;
}
}
/* jshint browser:true */
/* globals __OPTIONS__:true */
import LavaJs from './lava/Lava';
import {domLoaded} from './lava/Utils';
/**
* Assign the Lava.js module to the window and
* let $lava be an alias to the module.
*/
window.lava = new LavaJs();
/**
* If Lava.js was loaded from Lavacharts, the __OPTIONS__
* placeholder will be a JSON object of options that
* were set server-side.
*/
if (typeof __OPTIONS__ !== 'undefined') {
window.lava.options = __OPTIONS__;
}
/**
* If Lava.js was set to auto_run then once the DOM
* is ready, rendering will begin.
*/
if (window.lava.options.auto_run === true) {
domLoaded().then(() => {
window.lava.run();
});
}
/**
* Chart module
*
* @class Chart
* @module lava/Chart
* @author Kevin Hill <kevinkhill@gmail.com>
* @copyright (c) 2017, KHill Designs
* @license MIT
*/
import forIn from 'lodash/forIn';
import Renderable from './Renderable';
/**
* Chart class used for storing all the needed configuration for rendering.
*
* @typedef {Function} Chart
* @property {string} label - Label for the chart.
* @property {string} type - Type of chart.
* @property {Object} element - Html element in which to render the chart.
* @property {Object} chart - Google chart object.
* @property {string} package - Type of Google chart package to load.
* @property {boolean} pngOutput - Should the chart be displayed as a PNG.
* @property {Object} data - Datatable for the chart.
* @property {Object} options - Configuration options for the chart.
* @property {Object} events - Events and callbacks to apply to the chart.
* @property {Array} formats - Formatters to apply to the chart data.
* @property {Function} render - Renders the chart.
* @property {Function} uuid - Creates identification string for the chart.
*/
export default class Chart extends Renderable
{
/**
* Chart Class
*
* This is the javascript version of a lavachart with methods for interacting with
* the google chart and the PHP lavachart output.
*
* @param {object} json
* @constructor
*/
constructor (json) {
super(json);
this.formats = json.formats;
//this.events = typeof json.events === 'object' ? json.events : null;
this.pngOutput = typeof json.pngOutput === 'undefined' ? false : Boolean(json.pngOutput);
/**
* Any dependency on window.google must be in the render scope.
*/
this.render = () => {
this.setData(json.datatable);
this.gchart = new google.visualization[this.class](this.element);
this._attachEventRelays();
if (this.formats) {
this.applyFormats();
}
// if (this.events) {
// this._attachEvents();
// }
this.draw();
if (this.pngOutput) {
this.drawPng();
}
};
}
/**
* Draws the chart as a PNG instead of the standard SVG
*
* @public
* @external "chart.getImageURI"
* @see {@link https://developers.google.com/chart/interactive/docs/printing|Printing PNG Charts}
*/
drawPng() {
let img = document.createElement('img');
img.src = this.gchart.getImageURI();
this.element.innerHTML = '';
this.element.appendChild(img);
}
/**
* Apply the formats to the DataTable
*
* @param {Array} formats
* @public
*/
applyFormats(formats) {
if (! formats) {
formats = this.formats;
}
for (let format of formats) {
let formatter = new google.visualization[format.type](format.options);
console.log(`[lava.js] Column index [${format.index}] formatted with:`, formatter);
formatter.format(this.data, format.index);
}
}
/**
* Attach the defined chart event handlers.
*
* @private
*/
_attachEvents() {
forIn(this.events, (callback, event) => {
let context = window;
let func = callback;
if (typeof callback === 'object') {
context = context[callback[0]];
func = callback[1];
}
console.log(`[lava.js] The "${this.uuid}::${event}" event will be handled by "${func}" in the context`, context);
/**
* Set the context of "this" within the user provided callback to the
* chart that fired the event while providing the datatable of the chart
* to the callback as an argument.
*/
google.visualization.events.addListener(this.gchart, event, () => {
let callback = context[func].bind(this.gchart);
callback(this.data);
});
});
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment