I use Xampp to try GrapesJS, I downloaded GrapesJS from github then copied the rources to my HTDOCS folder, grap my Browser then hit Localhost :) it works, something like Web Builder appear and works as well, but how can I save the Edited Website using PHP ?,
I use intact INDEX.HTML found from GrapesJs github, only change it name to INDEX.PHP to work with PHP, so this is the codes I've been using
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>GrapesJS</title>
<link rel="stylesheet" href="dist/css/grapes.min.css">
<script src="dist/grapes.min.js"></script>
<style>
body,
html {
height: 100%;
margin: 0;
}
</style>
</head>
<body>
<div id="gjs" style="height:0px; overflow:hidden;">
<div class="panel">
<h1 class="welcome">Welcome to</h1>
<div class="big-title">
<svg class="logo" viewBox="0 0 100 100">
<path d="M40 5l-12.9 7.4 -12.9 7.4c-1.4 0.8-2.7 2.3-3.7 3.9 -0.9 1.6-1.5 3.5-1.5 5.1v14.9 14.9c0 1.7 0.6 3.5 1.5 5.1 0.9 1.6 2.2 3.1 3.7 3.9l12.9 7.4 12.9 7.4c1.4 0.8 3.3 1.2 5.2 1.2 1.9 0 3.8-0.4 5.2-1.2l12.9-7.4 12.9-7.4c1.4-0.8 2.7-2.2 3.7-3.9 0.9-1.6 1.5-3.5 1.5-5.1v-14.9 -12.7c0-4.6-3.8-6-6.8-4.2l-28 16.2"/>
</svg>
<span>GrapesJS</span>
</div>
<div class="description">
This is a demo content from index.html. For the development, you shouldn't edit this file, instead you can
copy and rename it to _index.html, on next server start the new file will be served, and it will be ignored by git.
</div>
</div>
<style>
.panel {
width: 90%;
max-width: 700px;
border-radius: 3px;
padding: 30px 20px;
margin: 150px auto 0px;
background-color: #d983a6;
box-shadow: 0px 3px 10px 0px rgba(0,0,0,0.25);
color:rgba(255,255,255,0.75);
font: caption;
font-weight: 100;
}
.welcome {
text-align: center;
font-weight: 100;
margin: 0px;
}
.logo {
width: 70px;
height: 70px;
vertical-align: middle;
}
.logo path {
pointer-events: none;
fill: none;
stroke-linecap: round;
stroke-width: 7;
stroke: #fff
}
.big-title {
text-align: center;
font-size: 3.5rem;
margin: 15px 0;
}
.description {
text-align: justify;
font-size: 1rem;
line-height: 1.5rem;
}
</style>
</div>
<script type="text/javascript">
var editor = grapesjs.init({
showOffsets: 1,
noticeOnUnload: 0,
container: '#gjs',
height: '100%',
fromElement: true,
storageManager: { autoload: 0 },
styleManager : {
sectors: [{
name: 'General',
open: false,
buildProps: ['float', 'display', 'position', 'top', 'right', 'left', 'bottom']
},{
name: 'Flex',
open: false,
buildProps: ['flex-direction', 'flex-wrap', 'justify-content', 'align-items', 'align-content', 'order', 'flex-basis', 'flex-grow', 'flex-shrink', 'align-self']
},{
name: 'Dimension',
open: false,
buildProps: ['width', 'height', 'max-width', 'min-height', 'margin', 'padding'],
},{
name: 'Typography',
open: false,
buildProps: ['font-family', 'font-size', 'font-weight', 'letter-spacing', 'color', 'line-height', 'text-shadow'],
},{
name: 'Decorations',
open: false,
buildProps: ['border-radius-c', 'background-color', 'border-radius', 'border', 'box-shadow', 'background'],
},{
name: 'Extra',
open: false,
buildProps: ['transition', 'perspective', 'transform'],
}
],
},
});
editor.BlockManager.add('testBlock', {
label: 'Block',
attributes: { class:'gjs-fonts gjs-f-b1' },
content: `<div style="padding-top:50px; padding-bottom:50px; text-align:center">Test block</div>`
})
</script>
</body>
</html>
thanks for your help
This way worked for me.
First added a Save button to grapesjs panel.
editor.Panels.addButton('options',
[{
id: 'save-db',
className: 'fas fa-save',
command: 'save-db',
attributes: {
title: 'Save Changes'
}
}]
);
Then added a command for save button.
editor.Commands.add('save-db', {
run: function(editor, sender) {
sender && sender.set('active', 0); // turn off the button
editor.store();
//storing values to variables
var htmldata = editor.getHtml();
var cssdata = editor.getCss();
$.post("save.php", {
//you can get value in post by calling this name
"htmldata": htmldata,
"cssdata": cssdata,
success: function(data) {
alert(data);
console.log("Success");
},
});
}
});
In save.php
$editor_html_content = $_POST['htmldata'];
$editor_css_content = $_POST['cssdata'];
editor.on('component:add', options => {
var html = editor.getHtml();
var css = editor.getCss();
function create () {
$.ajax({
url:base_url+"/savepagedata.php",
type: "post",
data: {html_data: html , css_data:css },
success:function(result){
console.log(result);
}
});
}
});
Related
I have a grid of cards with a button to remove each one of them with an animation. I chose to reduce the width to 0 so that the cards to the right (on the same row) slide to the left and occupy the removed card spot.
What I would like to achieve is to animate the first element of the following row into the last position of the row above (the one that had the card removed).
The best example I can provide is the home page of the Vivaldi browser, where you can remove a speed dial widget and the following ones animate to their new positions.
This example in CodePen is what I have so far.
$(document).ready(function() {
const content = $('#inner-content');
let listCourses = '';
let courses = [
{ title: 'html' },
{ title: 'css' },
{ title: 'javascript' },
{ title: 'python' },
{ title: 'react' },
{ title: 'node' },
{ title: 'angular' },
{ title: 'SEO' },
{ title: 'UX/UI' },
{ title: 'jQuery' },
{ title: 'SQL' },
{ title: 'noSql' }
]
courses.forEach((course) => {
let newCourse = `
<div class="course-container">
<div class="inner-container">
<h2>${course.title}</h2>
<button class="courses-control"> Remove </button>
</div>
</div>
`;
listCourses += newCourse;
});
content.html(listCourses);
$('.courses-control').on('click', function(e){
$(this)
.parents('.course-container').animate({
'width': '0px',
'padding': '12px 0px',
'opacity': '0'}, function() {
$(this).remove();
});
})
});
* {
box-sizing: border-box;
}
body { font-family: 'lato'; }
#inner-content {
display: flex;
flex-wrap: wrap;
}
.centered {
max-width: 960px;
margin: auto;
}
.course-container {
width: 25%;
padding: 12px;
overflow: hidden;
}
.inner-container {
overflow: hidden;
text-align: center;
border: 1px solid gray;
border-radius: 6px;
padding: 12px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>Courses</h1>
<div id="inner-content" class="centered">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="scripts.js"></script>
</body>
</html>
change the forEach loop to have an index and give each button an id:
courses.forEach((course, index) => {
let newCourse = `
<div class="course-container">
<div class="inner-container">
<h2>${course.title}</h2>
<button id="${index}" class="courses-control"> Remove </button>
</div>
</div>
`;
listCourses += newCourse;
});
Then in the click function after this:
$(this)
.parents('.course-container').animate({
'width': '0px',
'padding': '12px 0px',
'opacity': '0'
}, function () {
$(this).remove();
});
add this:
$(`#${Number(this.id) + 4}`).parents('.course-container').animate({
'margin-top': '-100px',
'z-index': '1',
'opacity': '0'
}, 500, function () {
$(this).css({ 'margin': '0px', 'opacity': '1' });
});
Try it out and tell me what you think...
I want to make a kinda hierarchical graph with JSCharting to upload in Google Data Studio showing a curriculum matrix network and its pre requisites.
I made a graph like this:
Each curriculum semester is a column and the classes are under each semester.
But I need to show the pre requisites network between these semesters.
For example:
EQ101 (in 1st Semester) is a pre requisite to take EQ201 (in 2nd Semester).
MA111 + MA141 (1st Semester) are pre requisites to take MA211 (in 2nd Semester).
How can I show these relationships when user pass the mouse over the classes?
The idea would be show the relationships like this picture, but only with animation with mouse over.
The code I made is like this:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Stacked HTML Node Chart | JSCharting</title>
<meta http-equiv="content-type" content="text-html; charset=utf-8" />
<script type="text/javascript" src="../jsc/jscharting.js"></script>
<script type="text/javascript" src="../jsc/modules/types.js"></script>
<link rel="stylesheet" type="text/css" href="css/default.css" />
<style type="text/css">
.department {
white-space: pre-wrap;
width: 110px;
padding: 5px;
color: #424242;
font-weight: normal;
}
.units {
white-space: pre-wrap;
width: 120px;
height: 200px;
color: #212121;
font-weight: normal;
text-align: center;
font-size: 10px;
}
.units li {
list-style-type: none;
padding: 5px;
margin: 4px 0;
border-radius: 5px;
}
.units ul {
padding: 0;
}
.units hr {
border: none;
background: white;
width: 40px;
height: 1px;
}
</style>
</head>
<body>
<div id="chartDiv" style="width: 810px; height: 430px; margin: 0px auto;"></div>
<script type="text/javascript">
/*
Chart with HTML annotations.
Learn how to:
- Create complex charts.
*/
// JS
var config = {
type: 'organization down',
defaultPoint: {
outline_width: 0,
annotation: {
asHTML: true,
label: {
text: '<div class="department" style="border-bottom:5px solid %color;"><b>%position</b>%name%units</div>',
align: 'center'
}
}
},
defaultSeries: {
mouseTracking_enabled: false,
line: { width: 1, color: '#e0e0e0' }
},
series: [
{
points: [
{
name: '',
id: 'dhr',
attributes: {
position: 'Engenharia Química<br>',
units: ''
},
label_style_fontSize: 14,
color: 'white'
},
{
name: '',
id: 'ca',
parent: 'dhr',
attributes: {
position: '1o Semestre<br>',
units: ''
},
label_style_fontSize: 12,
color: '#ba68c8'
},
{
name: '',
id: 'ca_',
parent: 'ca',
attributes: {
position: '',
units:
'<ul><li><b>EQ101</b><br>Introdução a Processos e Indústrias Químicas</li><li><b>F 128</b><br>Física Geral I</li><li><b>F 129</b><br>Física Experimental I</li><li><b>MA111</b><br>Cálculo I</li><li><b>MA141</b><br>Geometria Analítica e Vetores</li><li><b>GQ101</b><br>Química I</li><li><b>GQ102</b><br>Química Experimental I</li></ul>'
},
label_style_fontSize: 10,
color: '#ce93d8',
annotation_label_text: '<div class="units"><b>%position</b>%name%units</div>'
},
{
name: '',
id: 'ba',
parent: 'dhr',
attributes: {
position: '2o Semestre<br>',
units: ''
},
label_style_fontSize: 12,
color: '#f06292'
},
{
name: '',
id: 'ba_',
parent: 'ba',
attributes: {
position: '',
units:
"<ul><li><b>EQ201</b><br>Balanços de Massa e Energia</li><li><b>MA211</b><br>Cálculo II</li><li><b>MC102</b><br>Algoritmos e Programação de Computadores</li><li><b>ME414</b><br>Estatística para Experimentalistas</li><li><b>QI242</b><br>Química Inorgânica Teórica</li><li><b>QI244</b><br>Química Inorgânica Experimental</li></ul>"
},
label_style_fontSize: 10,
color: '#f48fb1',
annotation_label_text: '<div class="units"><b>%position</b>%name%units</div>'
},
{
name: '',
id: 'rm',
parent: 'dhr',
attributes: {
position: '3o Semestre<br>',
units: ''
},
label_style_fontSize: 12,
color: '#64b5f6'
},
{
name: '',
id: 'rm_',
parent: 'rm',
attributes: {
position: '',
units:
'<ul><li><b>CE304</b><br>Direito</li><li><b>F 328</b><br>Física Geral III</li><li><b>F 329</b><br>Física Experimental III</li><li><b>GT001</b><br>Ciência, Tecnologia e Sociedade</li><li><b>MA311</b><br>Cálculo III</li><li><b>QA313</b><br>Química III (Engenharia Química)</li><li><b>QO323</b><br>Química Orgânica I (Engenharia Química)</li></ul>'
},
label_style_fontSize: 10,
color: '#90caf9',
annotation_label_text: '<div class="units"><b>%position</b>%name%units</div>'
},
{
name: '',
id: 't',
parent: 'dhr',
attributes: {
position: '4o Semestre<br>',
units: ''
},
label_style_fontSize: 12,
color: '#4db6ac'
},
{
name: '',
id: 't_',
parent: 't',
attributes: {
position: '',
units:
'<ul><li><b>EM312</b><br>Desenho Técnico</li><li><b>EQ415</b><br>Termodinâmica I</li><li><b>EQ531</b><br>Aplicações dos Materiais em Engenharia Química</li><li><b>F 315</b><br>Mecânica Geral I</li><li><b>MS211</b><br>Cálculo Numérico</li><li><b>Q0422</b><br>Química Orgânica II (Engenharia Química)</li></ul>'
},
label_style_fontSize: 10,
color: '#80cbc4',
annotation_label_text: '<div class="units"><b>%position</b>%name%units</div>'
}
]
}
]
};
config.series[0].points.forEach(function(point) {
point.attributes.units = point.attributes.units.replace(/<li>/g, '<li style="background-color: %color;">');
});
var chart = JSC.chart('chartDiv', config);
</script>
</body>
</html>
I want to create a popout menu that is flush with the edge of the screen. It seems like popper doesn't like this because it always forces a margin of 5px. I've tried setting offset and padding values to 0, but it doesn't seem to work. Is there a way to do this without forcing it like
margin-left: -5px !important
Here are the tippy options ive included and a JSFiddle:
https://jsfiddle.net/tbgwknpf/1/
<div class="button">
click me!
<div id="menu-content">
this is a tippy!
</div>
</div>
</div>
body {
margin: 0;
}
.bar {
height: 100px;
width: 100%;
background: coral;
}
.button {
background: aquamarine;
height: 100%;
width: 200px;
display: flex;
align-items: center;
justify-content: center;
}
const menu = document.getElementById("menu-content");
menu.style.display = 'block';
tippy('.button',
{
content: menu,
allowHTML: true,
interactive: true,
trigger: 'click',
hideOnClick: 'toggle',
placement: 'bottom-start',
offset: [0, 0],
popperOptions: {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 0]
}
},
{
name: 'flip',
options: {
padding: 0,
flipVariations: false
}
}
]
},
});
If I add a margin to the button element, the tippy will align flush against the edge like I want it to. It is only when I ask it to be flush against the screen that it adds the translationX of 5px
You can do it using a theme.
JS:
tippy(targets, {
theme: "your-theme",
});
CSS:
.tippy-box[data-theme~="your-theme"] .tippy-content {
padding: 0;
}
Note the extra .tippy-content as the padding is in the child of .tippy-box.
You don't have to change any CSS styles. You just need to pass the right options to the underlying Popper.js:
popperOptions: {
modifiers: [
{
name: 'preventOverflow',
options: {
padding: 0,
},
},
],
},
I've got a CodePen of what I've created (with the help of other sources) and everything looks great. I want the ability to click on the text (or the page) and pause the JQuery loop. As well as the ability to click it again to resume it. CodePen Link
If that's too hard, I would like to look at the Next button so I can manually toggle to the next line, as well as a manual toggle button to the main line of <li>#SSBASKETBALL | SUMMERSERIES.NZ</li>
The button needs to be at the bottom further down as it's part of OBS's Browser tool.
If anyone could help me out with this, please feel free. It does the job at the moment, but I would really like to incorporate it more professionally and have more control over it. Cheers!
(function($) {
$.simpleTicker = function(element, options) {
var defaults = {
speed: 800,
delay: 10000,
easing: 'swing',
effectType: 'fade'
}
var param = {
'ul': '',
'li': '',
'initList': '',
'ulWidth': '',
'liHeight': '',
'tickerHook': 'tickerHook',
'effect': {}
}
var plugin = this;
plugin.settings = {}
var $element = $(element),
element = element;
plugin.init = function() {
plugin.settings = $.extend({}, defaults, options);
param.ul = element.children('ul');
param.li = element.find('li');
param.initList = element.find('li:first');
param.ulWidth = param.ul.width();
param.liHeight = param.li.height();
element.css({
height: (param.liHeight)
});
param.li.css({
top: '0',
left: '0',
position: 'absolute'
});
switch (plugin.settings.effectType) {
case 'fade':
plugin.effect.fade();
break;
case 'roll':
plugin.effect.roll();
break;
case 'slide':
plugin.effect.slide();
break;
}
plugin.effect.exec();
}
plugin.effect = {};
plugin.effect.exec = function() {
param.initList.css(param.effect.init.css)
.animate(param.effect.init.animate, plugin.settings.speed, plugin.settings.easing)
.addClass(param.tickerHook);
setInterval(function() {
element.find('.' + param.tickerHook)
.animate(param.effect.start.animate, plugin.settings.speed, plugin.settings.easing)
.next()
.css(param.effect.next.css)
.animate(param.effect.next.animate, plugin.settings.speed, plugin.settings.easing)
.addClass(param.tickerHook)
.end()
.appendTo(param.ul)
.css(param.effect.end.css)
.removeClass(param.tickerHook);
}, plugin.settings.delay);
}
plugin.effect.fade = function() {
param.effect = {
'init': {
'css': {
display: 'block',
opacity: '0'
},
'animate': {
opacity: '1',
zIndex: '98'
}
},
'start': {
'animate': {
opacity: '0'
}
},
'next': {
'css': {
display: 'block',
opacity: '0',
zIndex: '99'
},
'animate': {
opacity: '1'
}
},
'end': {
'css': {
display: 'none',
zIndex: '98'
}
}
}
}
plugin.effect.roll = function() {
param.effect = {
'init': {
'css': {
top: '-3em',
display: 'block',
opacity: '0'
},
'animate': {
top: '0',
opacity: '1',
zIndex: '98'
}
},
'start': {
'animate': {
top: '3em',
opacity: '0'
}
},
'next': {
'css': {
top: '-3em',
display: 'block',
opacity: '0',
zIndex: '99'
},
'animate': {
top: '0',
opacity: '1'
}
},
'end': {
'css': {
zIndex: '98'
}
}
}
}
plugin.effect.slide = function() {
param.effect = {
'init': {
'css': {
left: (-(200)),
display: 'block',
opacity: '0'
},
'animate': {
left: '0',
opacity: '1',
zIndex: '98'
}
},
'start': {
'animate': {
left: (200),
opacity: '0'
}
},
'next': {
'css': {
left: (param.ulWidth),
display: 'block',
opacity: '0',
zIndex: '99'
},
'animate': {
left: '0',
opacity: '1'
}
},
'end': {
'css': {
zIndex: '98'
}
}
}
}
plugin.init();
}
$.fn.simpleTicker = function(options) {
return this.each(function() {
if (undefined == $(this).data('simpleTicker')) {
var plugin = new $.simpleTiecker(this, options);
$(this).data('simpleTicker', plugin);
}
});
}
})(jQuery);
$(function() {
$.simpleTicker($('#js-ticker-fade'), {
'effectType': 'fade'
});
$.simpleTicker($('#js-ticker-roll'), {
'effectType': 'roll'
});
$.simpleTicker($('#js-ticker-slide'), {
'effectType': 'slide'
});
});
#font-face {
font-family: "DharmaGothicEW01-Light";
src: url("https:https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.eot");
src: url("https:https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.eot?#iefix") format("embedded-opentype"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.woff2") format("woff2"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.woff") format("woff"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.ttf") format("truetype"), url("https://db.onlinewebfonts.com/t/dcc1a03cbbd06fea7e48d65ff78624ef.svg#DharmaGothicEW01-Light") format("svg");
}
#font-face {
font-family: "DharmaGothicEW01-Bold";
src: url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.eot");
src: url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.eot?#iefix") format("embedded-opentype"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.woff2") format("woff2"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.woff") format("woff"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.ttf") format("truetype"), url("https://db.onlinewebfonts.com/t/5c5772b491b3e1c39beb61efcd6824f7.svg#DharmaGothicEW01-Bold") format("svg");
}
* {
font-size: 32px;
word-spacing: 5px;
font-family: DharmaGothicEW01-Light;
text-align: center;
color: #000;
}
.hvhbox {
display: inline-block;
width: 50px;
border: 0px solid #000;
background: #fe3249;
text-align: center;
}
.simple-ticker {
position: relative;
text-align: center;
width: 100%;
padding: 30px;
border: 0px solid #ddd;
overflow: hidden;
}
.simple-ticker ul {
position: relative;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
}
.simple-ticker ul li {
display: none;
width: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery simple news ticker</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<section>
<div class="simple-ticker" id="js-ticker-roll">
<ul>
<li>#SSBASKETBALL | SUMMERSERIES.NZ</li>
<li>THE SUMMER SERIES 20: <span style="background: #979797; color: #fff;"> HUTT VALLEY </span> VS <span style="background: #0053a3; color: #fff;"> UPPER HUTT </span></li>
<li>THE SUMMMER SERIES IS PROUDLY SUPPORTED BY TRIPLE THREAT</li>
<li><span style="background: #0053a3; color: #fff"> UHC </span> RJ WICHMAN 13 PTS</li>
<li><span style="background: #979797; color: #fff;"> HVH </span> 25% [1/4] 3PT PERCENTAGE 20% [1/5] <span style="background: #0053a3; color: #fff;"> UHC </span></li>
<!-- <li>NEXT UP: <span style="background: #fb1414; color: #fff;"> SACRED HEART </span> VS <span style="background: #fff200; color: #000;"> WELLINGTON EAST </span></li> -->
</ul>
</div>
</section>
<!-- partial -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js'></script>
<script src="./script.js"></script>
</body>
</html>
I develop the app that uses datatables to visualize certain statistics data.
I receive from API the data in the following format:
{
"data": [{
"companyName": "company1",
"growth": 15
},
{
"companyName": "company2",
"growth": -8
},
{
"companyName": "company3",
"growth": 23
}]
}
Which is essentially a company name and its year over year revenue growth figure (%).
What I would like to implement is an MS Excel-like conditional formatting feature that displays colored bars inside percentage cells (color of the bar is red for negative and green for positive values and its size is normalized to minimal/maximal value and column width).
So far, my HTML is:
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js" charset="utf8"></script>
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.js"></script>
<table id="revenue-growth"></table>
And jQuery:
$('#revenue-growth').DataTable({
ajax: {
url: 'https://192.168.0.1/revenue',
method: 'GET',
dataSrc: 'data'
}
dom: 'Bfrtip',
pageLength: 50,
order: [0, 'asc']
columDefs: [{
targets: 0,
data: 'companyName',
title: 'Company Name'
}, {
targets: 1,
data: 'growth',
title: 'YoY revenue growth, %'
}
]
})
So, my question is: is there a way to implement such feature from the ground up, or, maybe, there's already plug-in that does exactly this?
I didn't find anything matching my request here, at stackoverflow, nor I was able to identify DataTables API methods that may solve my problem, so I would really appreciate that if you could point me to the right direction.
You could use the render-callback to create bars inside the cells in the growth-column.
You have to find the maximum growth inside the dataset.
In the render-callback:
2.1. check if the growth is negative or positive.
2.2. calculate bar width-% based on the growth and the maximum.
2.3. create and append the elements based on these information.
Here is an simple example:
$(document).ready(function() {
const dataSet = [
{ companyName: "Company A", growth: -12 },
{ companyName: "Company B", growth: 31 },
{ companyName: "Company C", growth: 7 },
{ companyName: "Company D", growth: 0 },
{ companyName: "Company E", growth: -29 },
{ companyName: "Company F", growth: 23 },
];
// Get absolute maximum value of grwoth from dataset
const maxGrowthValue = Math.max.apply(Math, dataSet.map(function(item) { return Math.abs(item.growth); }));
const table = $('#example').DataTable({
data: dataSet,
columns: [
{
data: 'companyName',
title: "Company Name",
},
{
data: 'growth',
title: "YoY revenue growth, %",
// Custom render the cell of the growth-column
render: (data, type, row, meta) => {
const isPositive = (Number(data) > 0);
const barWidth = 100 / maxGrowthValue * Math.abs(Number(data)) * 0.5;
const $growthBarContainer = $('<div>', {
class: "growth-bar",
});
const $growthBar = $('<div>', {
class: "bar bar-" + (isPositive ? 'positive' : 'negative'),
});
$growthBar.css({
width: barWidth.toFixed(2) + '%',
});
$growthBarContainer.append($growthBar);
$growthNumber = $('<div>', {
class: "growth-number",
});
$growthNumber.text(data + '%');
$growthBarContainer.append($growthNumber);
return $growthBarContainer.prop("outerHTML");
},
},
],
});
});
.growth-bar {
display: inline-block;
width: 120px;
height: 12px;
position: relative;
background-color: #eee;
border: 1px solid #424242;
}
.growth-bar > .bar {
width: 0%;
height: 100%;
position: absolute;
}
.growth-bar > .bar.bar-negative {
right: 50%;
background-color: red;
}
.growth-bar > .bar.bar-positive {
left: 50%;
background-color: green;
}
.growth-bar > .growth-number {
position: absolute;
top: 1px;
right: 2px;
color: #fff;
/* shadow for better readability */
text-shadow: 0px -1px 0px rgba(0,0,0,.5), 0px 1px 0px rgba(0,0,0,.5), -1px 0px 0px rgba(0,0,0,.5), 1px 0px 0px rgba(0,0,0,.5), 0px 0px 1px rgba(0,0,0,.25), 0px 0px 2px rgba(0,0,0,.5), 0px 0px 3px rgba(0,0,0,.75);
font-size: 10px;
line-height: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<table id="example" class="display" style="width:100%"></table>