While horizontal scrolling the datalabels of charjs is overlapping to y-axis - charts

To show all bars I have set the horizontal scrolling to chartjs in Ionic angular project , and i have used the DataLabelsPlugin constant for bars label. and while scrolling the datalabels is overlapping with y-axis its not hiding before y-axis like bars.
and also horizontal scroll is not happening smoothly.
graph working fine as a expected output
marked with issue about - after scrolling the datalabels went over the y-axis not hide below y-axis like bars
I have tried to add and used the custom datalabels but same issue i am getting and i didnt find any css or attribute on 'https://www.chartjs.org/docs/latest/' official site or not on any other sites -> to hide the datalabels from over the y-axis.
ts file code:
createBarChart() {
const footer = (tooltipItems) => {
let sum = 0;
tooltipItems.forEach(function(tooltipItem) {
sum += tooltipItem.parsed.y;
});
return this.util.getFormatValue(sum)+'%';
};
const toolLabel = (tooltipItems) => {
return "";
};
const toolTitle = (tooltipItems) => {
var string_to_array = function (str) {
return str.trim().split("#$#$");
};
var ss;
tooltipItems.forEach(function(tooltipItem) {
ss = string_to_array(tooltipItem.label.replace(/(.{40})/g, "$1#$#$"))
});
return ss;
};
let graphSize = Math.max(...this.daywise_occupancy);
if(graphSize == 0){
graphSize =1;
}
const plugin = {
id: 'customCanvasBackgroundColor',
beforeDraw: (chart, args, options) => {
const {ctx} = chart;
ctx.save();
ctx.globalCompositeOperation = 'destination-over';
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, chart.width, chart.height);
ctx.restore();
}
};
this.bars = new Chart(this.barchart6.nativeElement, {
type: 'bar',
data: {
labels: this.daywise_date,
datasets: [{
data: this.daywise_occupancy,
backgroundColor: function(context) {
var value = context.dataset.data[context.dataIndex];
return value <= 15 ? '#f95959'
: value > 15 && value <=60 ? '#F5A623'
: '#00ADB5'
},
borderColor: function(context) {
var value = context.dataset.data[context.dataIndex];
return value <= 15 ? '#f95959'
: value > 15 && value <=60 ? '#F5A623'
: '#00ADB5'
},
borderWidth: 1,
barThickness:30,
}]
},
plugins: [DataLabelsPlugin,plugin],
options: {
animations: {
tension: {
duration: 1000,
easing: 'linear',
from: 1,
to: 0,
loop: true
}
},
scales: {
x: {
min:0,
max:5,
ticks : {
maxRotation: 70,
minRotation: 70,
font:{
size:10,
},
callback: function(value : any, index, ticks_array) {
let characterLimit = 12;
let label = this.getLabelForValue(value);
if ( label.length >= characterLimit) {
return label.slice(0, label.length).substring(0, characterLimit -1).trim() + '..';
}
return label;
}
}
},
y: { // defining min and max so hiding the dataset does not change scale range
min: 0,
max: this.loader.getGraphsizeRound(graphSize),
title: { display: true, text: (this.titleSet)? '% of Branches Contribution' : '% of Seat Occupancy' },
beginAtZero: true,
display: true,
position: 'left',
// ticks: {
// stepSize: 6,
// },
}
},
plugins: {
legend: {
display: false
},
datalabels:{
anchor: 'end',
align: 'end',labels: {
value: {
color: '#2C3A45;',
formatter: function (value) {
// return Math.round(value) + '%';
return value + '%';
},
font:{
weight:700,
size:14
}
}
}
},
tooltip: {
callbacks: {
footer:footer,
label: toolLabel,
title:toolTitle
},
displayColors:false
}
}
}
});
this.bars.canvas.addEventListener('touchmove',(eve) => {
this.touchmove(eve,this.bars)
});
this.bars.canvas.addEventListener('touchstart',(eve) => {
this.touchstart(eve)
});
}
touchstart(e)
{
this.startX = e.touches[0].clientX;
this.startY = e.touches[0].clientY;
}
touchmove(e,chart)
{
var deltaX = e.touches[0].clientX - this.startX,
deltaY = e.touches[0].clientY - this.startY;
const dataLength = chart.data.labels.length;
let min = chart.options.scales.x.min;
if(deltaX < 0){
if( chart.options.scales.x.max >= dataLength ){
chart.options.scales.x.min = dataLength - 5;
chart.options.scales.x.max = dataLength;
}else{
chart.options.scales.x.min += 1;
chart.options.scales.x.max += 1;
}
// console.log( chart.options.scales.x.min);
// chart1line.options.scales.y.max = graphSize
}else if(deltaX > 0){
if( chart.options.scales.x.min <= 0 ){
chart.options.scales.x.min = 0;
chart.options.scales.x.max = 4;
}else{
chart.options.scales.x.min -= 1;
chart.options.scales.x.max -= 1;
}
}else{
}
chart.update();
}
HTML code:
<div class="chartWrapper">
<div class="chartAreaWrapper">
<canvas #barchart6 height="190" max-height="190" width="0"></canvas>
</div>
</div>
My expected output
horizontal scroll work smoothly.
after scrolling label should not overlap on y-axis.

Related

change tooltip color in amchart

I want to change the background colour of the tooltip value in Amchart 5.
I mean the black background colour.
You can create an instance of Tooltip and store it in a variable. Use it in your valueAxis configuration, then modify the background color of your tooltip through its background element.
let tooltip = am5.Tooltip.new(root, {});
let valueAxis = mainPanel.yAxes.push(
am5xy.ValueAxis.new(root, {
// ...
tooltip,
// ...
})
);
tooltip.get("background").set("fill", am5.color(0x0000ff));
Full example (using this demo from the official website):
am5.ready(function() {
// Create root element
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
let root = am5.Root.new("chartdiv");
// Set themes
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([am5themes_Animated.new(root)]);
// Create a stock chart
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Instantiating_the_chart
let stockChart = root.container.children.push(
am5stock.StockChart.new(root, {})
);
// Set global number format
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/concepts/formatters/formatting-numbers/
root.numberFormatter.set("numberFormat", "#,###.00");
// Create a main stock panel (chart)
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Adding_panels
let mainPanel = stockChart.panels.push(
am5stock.StockPanel.new(root, {
wheelY: "zoomX",
panX: true,
panY: true
})
);
// Create value axis
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
let tooltip = am5.Tooltip.new(root, {});
let valueAxis = mainPanel.yAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {
pan: "zoom"
}),
extraMin: 0.1, // adds some space for for main series
tooltip,
numberFormat: "#,###.00",
extraTooltipPrecision: 2
})
);
tooltip.get("background").set("fill", am5.color(0x0000ff));
let dateAxis = mainPanel.xAxes.push(
am5xy.GaplessDateAxis.new(root, {
baseInterval: {
timeUnit: "minute",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {}),
tooltip: am5.Tooltip.new(root, {})
})
);
// add range which will show current value
let currentValueDataItem = valueAxis.createAxisRange(valueAxis.makeDataItem({ value: 0 }));
let currentLabel = currentValueDataItem.get("label");
if (currentLabel) {
currentLabel.setAll({
fill: am5.color(0xffffff),
background: am5.Rectangle.new(root, { fill: am5.color(0x000000) })
})
}
let currentGrid = currentValueDataItem.get("grid");
if (currentGrid) {
currentGrid.setAll({ strokeOpacity: 0.5, strokeDasharray: [2, 5] });
}
// Add series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
let valueSeries = mainPanel.series.push(
am5xy.CandlestickSeries.new(root, {
name: "AMCH",
clustered: false,
valueXField: "Date",
valueYField: "Close",
highValueYField: "High",
lowValueYField: "Low",
openValueYField: "Open",
calculateAggregates: true,
xAxis: dateAxis,
yAxis: valueAxis,
legendValueText:
"open: [bold]{openValueY}[/] high: [bold]{highValueY}[/] low: [bold]{lowValueY}[/] close: [bold]{valueY}[/]",
legendRangeValueText: ""
})
);
// Set main value series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series
stockChart.set("stockSeries", valueSeries);
// Add a stock legend
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/stock-legend/
let valueLegend = mainPanel.plotContainer.children.push(
am5stock.StockLegend.new(root, {
stockChart: stockChart
})
);
// Set main series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series
valueLegend.data.setAll([valueSeries]);
// Add cursor(s)
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
mainPanel.set(
"cursor",
am5xy.XYCursor.new(root, {
yAxis: valueAxis,
xAxis: dateAxis,
snapToSeries: [valueSeries],
snapToSeriesBy: "y!"
})
);
// Add scrollbar
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/
let scrollbar = mainPanel.set(
"scrollbarX",
am5xy.XYChartScrollbar.new(root, {
orientation: "horizontal",
height: 50
})
);
stockChart.toolsContainer.children.push(scrollbar);
let sbDateAxis = scrollbar.chart.xAxes.push(
am5xy.GaplessDateAxis.new(root, {
baseInterval: {
timeUnit: "minute",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {})
})
);
let sbValueAxis = scrollbar.chart.yAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
})
);
let sbSeries = scrollbar.chart.series.push(
am5xy.LineSeries.new(root, {
valueYField: "Close",
valueXField: "Date",
xAxis: sbDateAxis,
yAxis: sbValueAxis
})
);
sbSeries.fills.template.setAll({
visible: true,
fillOpacity: 0.3
});
// Data generator
let firstDate = new Date();
let lastDate;
let value = 1200;
// data
function generateChartData() {
let chartData = [];
for (var i = 0; i < 50; i++) {
let newDate = new Date(firstDate);
newDate.setMinutes(newDate.getMinutes() - i);
value += Math.round((Math.random() < 0.49 ? 1 : -1) * Math.random() * 10);
let open = value + Math.round(Math.random() * 16 - 8);
let low = Math.min(value, open) - Math.round(Math.random() * 5);
let high = Math.max(value, open) + Math.round(Math.random() * 5);
chartData.unshift({
Date: newDate.getTime(),
Close: value,
Open: open,
Low: low,
High: high
});
lastDate = newDate;
}
return chartData;
}
let data = generateChartData();
// set data to all series
valueSeries.data.setAll(data);
sbSeries.data.setAll(data);
// update data
let previousDate;
setInterval(function() {
let valueSeries = stockChart.get("stockSeries");
let date = Date.now();
let lastDataObject = valueSeries.data.getIndex(valueSeries.data.length - 1);
if (lastDataObject) {
let previousDate = lastDataObject.Date;
let previousValue = lastDataObject.Close;
value = am5.math.round(previousValue + (Math.random() < 0.5 ? 1 : -1) * Math.random() * 2, 2);
let high = lastDataObject.High;
let low = lastDataObject.Low;
let open = lastDataObject.Open;
if (am5.time.checkChange(date, previousDate, "minute")) {
open = value;
high = value;
low = value;
let dObj1 = {
Date: date,
Close: value,
Open: value,
Low: value,
High: value
};
valueSeries.data.push(dObj1);
sbSeries.data.push(dObj1);
previousDate = date;
} else {
if (value > high) {
high = value;
}
if (value < low) {
low = value;
}
let dObj2 = {
Date: date,
Close: value,
Open: open,
Low: low,
High: high
};
valueSeries.data.setIndex(valueSeries.data.length - 1, dObj2);
sbSeries.data.setIndex(sbSeries.data.length - 1, dObj2);
}
// update current value
if (currentLabel) {
currentValueDataItem.animate({ key: "value", to: value, duration: 500, easing: am5.ease.out(am5.ease.cubic) });
currentLabel.set("text", stockChart.getNumberFormatter().format(value));
let bg = currentLabel.get("background");
if (bg) {
if(value < open){
bg.set("fill", root.interfaceColors.get("negative"));
}
else{
bg.set("fill", root.interfaceColors.get("positive"));
}
}
}
}
}, 1000);
}); // end am5.ready()
#chartdiv {
width: 100%;
height: 350px;
}
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/stock.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<div id="chartdiv"></div>

Donut chart with custom tooltip using Chartist in React

I am creating a donut chart using Chartist but unable to add a custom tooltip with resize slice on the mouse hover event. Chartist "Draw" method is rerender on changing the position of mouse on hover of the chart
I pasted my code as below:
/* eslint-disable no-unused-vars */
import React, {useState} from 'react'
import PropTypes from 'prop-types'
import ChartistGraph from 'react-chartist'
import Chartist from 'chartist'
import styles from './MyChart.scss'
import {formatNumber} from '../../../../utils/formatter'
import MyChartInfo from './MyChartInfo'
function MyChart ({ dataSeries, getDetailsTable }) {
const [changePercent, setChangePercent] = useState(0)
const [showToolTip, setShowToolTip] = useState(false)
const [myChartInfoDetails, setMyChartInfoDetails] = useState({sectorName: '', changePercent: ''})
const [toolTipPosition, setToolTipPosition] = useState({})
function setToolTip () {
const PopOverData = [myChartInfoDetails.sectorName || '', `% Return: ${myChartInfoDetails.changePercent || ''}`, '(Click to view top & worst performing equities)']
return (<MyChartInfo dataTable={PopOverData} style={toolTipPosition} />)
}
let pieOptions = {
width: '520px',
height: '520px',
donut: true,
donutWidth: 150,
donutSolid: false,
startAngle: 270,
showLabel: true,
chartPadding: 60,
labelOffset: 105,
labelDirection: 'explode',
labelInterpolationFnc: function (value) {
return value
}
}
let pieData = {
series: dataSeries && dataSeries.length > 0 ? dataSeries.map(item => Math.abs(item.value)) : [100],
labels: dataSeries && dataSeries.length > 0 ? dataSeries.map(item => item.name.concat('<br>', formatNumber(item.value, {precision: 2, negSign: true, posSign: true}))) : ['']
}
// eslint-disable-next-line no-unused-vars
const listner = {
created: (chart) => {
const chartPie = document.querySelectorAll('.ct-chart-donut .ct-slice-donut')
chartPie && chartPie.forEach((pie) => {
pie.addEventListener('mouseenter', (e) => {
e.stopPropagation()
pie.setAttribute('style', 'stroke-width: 170px;')
console.log('hover aa ', changePercent, Math.abs(pie.getAttribute('ct:value')))
setChangePercent(Math.abs(pie.getAttribute('ct:value')))
let topPosition = e.layerY + 30
let leftPosition = e.layerX + 30
setToolTipPosition({top: topPosition, left: leftPosition})
const myChartData = dataSeries.find(sector => Math.abs(sector.value) === Math.abs(pie.getAttribute('ct:value')))
setSectorDetails({sectorName: myChartData.name, changePercent: myChartData.value})
setShowToolTip(true)
})
pie.addEventListener('mouseleave', (e) => {
pie.setAttribute('style', 'stroke-width: 150px;')
setShowToolTip(false)
})
pie.addEventListener('click', (e) => {
const Id = dataSeries.find(sector => Math.abs(sector.value) === Math.abs(pie.getAttribute('ct:value'))).id.toString()
console.log('click ', Id, pie.getAttribute('ct:value'))
getDetailsTable(Id)
})
})
},
draw: (data) => {
// console.log('data', data)
if (data.type === 'slice') {
// Get the total path length in order to use for dash array animation
var pathLength = data.element._node.getTotalLength()
// Set a dasharray that matches the path length as prerequisite to animate dashoffset
data.element.attr({
'stroke-dasharray': pathLength + 'px ' + pathLength + 'px'
})
let noOfNonZeros = dataSeries.length > 0 && dataSeries.filter(e => e.value > 0).length
// Create animation definition while also assigning an ID to the animation for later sync usage
var animationDefinition = {
'stroke-dashoffset': {
id: 'anim' + data.index,
dur: 1,
from: -pathLength + 'px',
to: noOfNonZeros > 1 ? '2px' : '0px',
easing: Chartist.Svg.Easing.easeOutQuint,
// We need to use `fill: 'freeze'` otherwise our animation will fall back to initial (not visible)
fill: 'freeze'
}
}
// If this was not the first slice, we need to time the animation so that it uses the end sync event of the previous animation
if (data.index !== 0) {
animationDefinition['stroke-dashoffset'].begin = 'anim' + (data.index - 1) + '.end'
}
// We need to set an initial value before the animation starts as we are not in guided mode which would do that for us
data.element.attr({
'stroke-dashoffset': -pathLength + 'px'
})
// We can't use guided mode as the animations need to rely on setting begin manually
// See http://gionkunz.github.io/chartist-js/api-documentation.html#chartistsvg-function-animate
data.element.animate(animationDefinition, false)
if (dataSeries.length === 0) {
data.element._node.setAttribute('data-value', 'no-composition')
}
}
if (data.type === 'label') {
let textHtml = ['<p>', data.text, '</p>'].join('')
let multilineText = Chartist.Svg('svg').foreignObject(
textHtml,
{
style: 'overflow: visible;',
x: data.x - 30,
y: data.y - 30,
width: 90,
height: 30
},
'ct-label'
)
data.element.replace(multilineText)
}
}
}
return (
<div data-testid='gPieChart' id='performance_chart'>
{<ChartistGraph
data={pieData}
options={pieOptions}
type='Pie'
style={{ width: '100%', height: '100%' }}
className={styles.MyChart}
listener={listner}
/>
}
{showToolTip && setToolTip()}
</div>
)
}
MyChart.propTypes = {
dataSeries: PropTypes.array,
getDetailsTable: PropTypes.func
}
export default MyChart
Output
I want to add a custom tooltip with resize slice functionality on mouse hover event

Click event don't fire on first slide ion-slide

Created a slider with ion-slides. But sometimes first and the last slide of slider don't fire the click event. Like we are displaying five slides: 2,3,4 slides fire event with no error and in 1,4 it doesn't fire click event neither shows any error.
Please me the solution. Thanks in advance
.html file
<ion-grid>
<ion-row>
<ion-col size="12" class="p-0">
<ion-slides pager="false" #slideWithNav
(ionSlideDidChange)="SlideDidChange(sliderOne,slideWithNav)" class="pb-10">
<ion-slide tappable *ngFor="let s of sliderOne.slidesItems" (click)="openModal(s)">
<div>
<h6 class="m-5 cardTtl">{{s.name}}</h6>
</div>
</ion-slide>
</ion-slides>
</ion-col>
</ion-row>
.js file
let slides = document.querySelector('ion-slides');
const slideOpts = {
grabCursor: true,
centeredSlides: true,
slidesPerView: 2.45,
initialSlide: 1,
pager: true,
loop: true,
autoplay:false,
coverflowEffect: {
rotate: 5,
stretch: 0,
depth: 100,
modifier: 1,
slideShadows: true,
},
pagination: {
el: '.swiper-pagination',
},
on: {
beforeInit() {
const swiper = this;
swiper.classNames.push(`${swiper.params.containerModifierClass}coverflow`);
swiper.classNames.push(`${swiper.params.containerModifierClass}3d`);
swiper.params.watchSlidesProgress = true;
swiper.originalParams.watchSlidesProgress = true;
},
setTranslate() {
const swiper = this;
const {
width: swiperWidth, height: swiperHeight, slides, $wrapperEl, slidesSizesGrid, $
} = swiper;
const params = swiper.params.coverflowEffect;
const isHorizontal = swiper.isHorizontal();
const transform$$1 = swiper.translate;
const center = isHorizontal ? -transform$$1 + (swiperWidth / 2) : -transform$$1 + (swiperHeight / 2);
const rotate = isHorizontal ? params.rotate : -params.rotate;
const translate = params.depth;
// Each slide offset from center
for (let i = 0, length = slides.length; i < length; i += 1) {
const $slideEl = slides.eq(i);
const slideSize = slidesSizesGrid[i];
const slideOffset = $slideEl[0].swiperSlideOffset;
const offsetMultiplier = ((center - slideOffset - (slideSize / 2)) / slideSize) * params.modifier;
let rotateY = isHorizontal ? rotate * offsetMultiplier : 0;
let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier;
// var rotateZ = 0
let translateZ = -translate * Math.abs(offsetMultiplier * 6.2);
let translateY = isHorizontal ? 0 : params.stretch * (offsetMultiplier);
let translateX = isHorizontal ? params.stretch * (offsetMultiplier) : 0;
// Fix for ultra small values
if (Math.abs(translateX) < 0.001) translateX = 0;
if (Math.abs(translateY) < 0.001) translateY = 0;
if (Math.abs(translateZ) < 0.001) translateZ = 0;
if (Math.abs(rotateY) < 0.001) rotateY = 0;
if (Math.abs(rotateX) < 0.001) rotateX = 0;
const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
$slideEl.transform(slideTransform);
$slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1;
if (params.slideShadows) {
// Set shadows
let $shadowBeforeEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top');
let $shadowAfterEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom');
if ($shadowBeforeEl.length === 0) {
$shadowBeforeEl = swiper.$(`<div class="swiper-slide-shadow-${isHorizontal ? 'left' : 'top'}"></div>`);
$slideEl.append($shadowBeforeEl);
}
if ($shadowAfterEl.length === 0) {
$shadowAfterEl = swiper.$(`<div class="swiper-slide-shadow-${isHorizontal ? 'right' : 'bottom'}"></div>`);
$slideEl.append($shadowAfterEl);
}
if ($shadowBeforeEl.length) $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0;
if ($shadowAfterEl.length) $shadowAfterEl[0].style.opacity = (-offsetMultiplier) > 0 ? -offsetMultiplier : 0;
}
}
// Set correct perspective for IE10
if (swiper.support.pointerEvents || swiper.support.prefixedPointerEvents) {
const ws = $wrapperEl[0].style;
ws.perspectiveOrigin = `${center}px 50%`;
}
},
setTransition(duration) {
const swiper = this;
swiper.slides
.transition(duration)
.find('.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left')
.transition(duration);
}
}
}
slides.options = slideOpts;
.ts file
constructor(public modalController: ModalController) {
$.getScript('assets/js/slider.js');
this.sliderOne =
{
isBeginningSlide: true,
isEndSlide: false,
slidesItems: [
{ id: 0, name: 'text1' },
{ id: 1, name: 'text2' },
{ id: 2, name: 'text3' },
{ id: 3, name: 'text4' }
],
};
}
async openModal(s) {
const modal = await this.modalController.create({
component: SliderPage,
componentProps: {
titleName: s.name
}
});
return await modal.present();
}

How create a HexagonLayer with log size scale

I've created a layer in 3D that render and works perfectly.
I want to create a HexagonLayer where his elevation will be based on SUM of all volumes that I think I'm doing correctly.
But I don't know do that size scale should by log as you can see in kepler image.
How can work with log size scale??
Here is my code:
const BLUE_COLORS = [
[230, 250, 250],
[193, 229, 230],
[157, 208, 212],
[117, 187, 193],
[75, 167, 175],
[0, 147, 156],
];
const material = {
ambient: 0.64,
diffuse: 0.6,
shininess: 32,
specularColor: [51, 51, 51],
};
class DeckGLOverlay extends Component {
constructor(props) {
super(props);
this.state = {
x: null,
y: null,
hoveredObject: null,
id: uuidv4(),
};
}
getCoordinates = () => {
let coordinates = [];
const { data3d } = this.props;
data3d.forEach(supplypoint => {
if (
!supplypoint.geojson ||
(supplypoint.geojson &&
supplypoint.geojson &&
!supplypoint.geojson.coordinates)
) {
return;
}
let feature = {
COORDINATES: supplypoint.geojson.coordinates,
VOLUME: supplypoint.value,
UNITS: supplypoint.units,
DATA: {
supplypointId: supplypoint.supplypointId,
address: supplypoint.address,
client: supplypoint.client,
diameter: supplypoint.diameter,
endusetype: supplypoint.endusetype,
usetype: supplypoint.usetype,
},
};
coordinates.push(feature);
});
return coordinates;
};
sumElevations = values => {
if (values.length >= 1) {
let totalVolumes = 0;
for (let item of values) {
if (item.hasOwnProperty("VOLUME")) {
totalVolumes += item["VOLUME"];
}
}
return totalVolumes;
}
return 0;
};
render() {
const { viewport } = this.props;
const layers = [];
if (this.props.data3d) {
layers.push(
new HexagonLayer({
id: `hexagon-layer-${uuidv4()}`,
data: this.getCoordinates(),
pickable: true,
extruded: true,
material: material,
radius: 5,
elevationRange: [0, 1000],
elevationScale: 1,
elevationAggregation: "SUM",
colorRange: BLUE_COLORS,
colorScaleType: "quantile",
colorAggregation: "SUM",
getPosition: d => d.COORDINATES,
getElevationValue: d => this.sumElevations(d),
})
);
}
return (
<DeckGL layers={layers} onHover={this.onHoverDeckgl} viewState={viewport} />
);
}
}
export default injectIntl(DeckGLOverlay);
Image
I've used scaleLag from d3-scale, from d3-scale library.
Solution:
class DeckGLOverlay extends Component {
constructor(props) {
super(props);
this.state = {
x: null,
y: null,
hoveredObject: null,
id: uuidv4(),
};
this.rangeColor = null;
this.logScale = scaleLog()
.domain([10, 100000])
.range([0, 500]);
}
getCoordinates = () => {
...
return coordinates;
};
sumElevations = values => {
if (values.length >= 1) {
let totalVolumes = 0;
for (let item of values) {
if (item.hasOwnProperty("VOLUME")) {
totalVolumes += item["VOLUME"];
}
}
return totalVolumes;
}
return 0;
};
elevationByLogScale = values => {
let totalVolumes = this.sumElevations(values);
let scale = parseInt(this.logScale(totalVolumes));
if (isNaN(scale)) return 0;
return scale;
};
render() {
const { viewport } = this.props;
const layers = [];
if (this.props.data3d) {
layers.push(
new HexagonLayer({
id: `hexagon-layer-${uuidv4()}`,
data: this.getCoordinates(),
pickable: true,
extruded: true,
radius: 5,
elevationRange: [0, 500],
elevationScale: 1,
colorRange: BLUE_COLORS,
getPosition: d => d.COORDINATES,
getElevationValue: d => this.elevationByLogScale(d),
})
);
}
return (
<DeckGL layers={layers} viewState={viewport} />
);
}
}

highcharts can't render

I use Ajax to get data, when I debug with firebug, the result shows highcharts option's data has data. But the chart can't render correctly. The charts background is rended correctely, but there is no chart.
here is my code.
// # author:wang
var chart;
var element;
var chart_type_element;
var y_title_1;
var y_title_2;
var y_title_3;
var date = new Date();
var y = date.getUTCFullYear();
var m = date.getUTCMonth();
var d = date.getUTCDate()-1;
var h = date.getUTCHours();
var minute = date.getUTCMinutes();
/**
* 返回图表的类型
*
*/
function chart_type(element){
var type;
var wind = '风向风速';
var t_h = '温湿度';
if ( element== 'wind' ){
type = wind;
} else if ( element == 't_h') {
type = t_h;
}
return type;
}
/**
*
*return y-axis title
*
*/
function y_title(element, serie){
var title;
if ( element== 'wind' ){
switch (serie){
case 1: title = '风速'; break;
case 2: title = '阵风'; break;
case 3: title = '风向'; break;
}
} else if ( element == 't_h') {
switch (serie){
case 1: title = '温度'; break;
case 2: title = '湿度'; break;
default: title = '';
}
}
return title;
}
function getLocTime(nS) {
return new Date(parseInt(nS)).toLocaleString().replace(/年|月/g, "-").replace(/日/g, " ");
}
/**
* 气压配置选项
*/
var option_p = {
chart: {
renderTo: 'station_curve',
zoomType: 'x'
},
title:{
text:'气压序列图'
},
subtitle: {
text: '信科气象台'
},
xAxis: {
type: 'datetime',
maxZoom: 3600000, // one hour
title: {
text: null
}
},
yAxis: {
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}],
min:980,
max:1040
},
tooltip: {
formatter: function() {
return getLocTime(this.x) +': '+ this.y;
}
},
legend: {
layout: 'vertical',
align: 'left',
x: 220,
verticalAlign: 'top',
y: 30,
floating: true,
backgroundColor: '#FFFFFF'
},
series: [{
name: '海平面气压',
color: '#4572A7',
type: 'line',
pointInterval: 60 * 1000,
pointStart: Date.UTC(y,m,d,h,minute),
marker: {
enabled: false
}
}, {
name: '甲板气压',
type: 'line',
color: '#AA4643',
pointInterval: 60 * 1000,
pointStart: Date.UTC(y,m,d,h,minute),
marker: {
enabled: false
}
}/*, {
name: '3',
color: '#89A54E',
pointInterval: 60 * 1000,
pointStart: Date.UTC(y,m,d,h,minute),
type: 'spline',
marker: {
enabled: false
}
}*/]
};
function draw_curve(platformID,element){
option.series[0].data = [];
option.series[1].data = [];
option_th.series[0].data = [];
option_th.series[1].data = [];
jQuery.getJSON('get_last_3d.php',{platformID:platformID,element:element}, function(data) {
var serie=[];
var serie1=[];
if (element == 'wind_dir'){
$.each(data,function(i,value){
serie[i]=parseInt(value.wd);
});
option.series[0].data = serie.reverse();
} else if (element == 'wind_speed'){
$.each(data,function(i,value){
serie[i]=parseInt(value.ws);
serie1[i]=parseInt(value.ws_max);
});
option_wind_speed.series[0].data = serie.reverse();
option_wind_speed.series[1].data = serie1.reverse();
} else if (element == 't_h') {
$.each(data,function(i,value){
serie[i]=parseInt(value.t);
serie1[i]=parseInt(value.h);
});
option_th.series[0].data = serie.reverse();
option_th.series[1].data = serie1.reverse();
} else if (element == 'p') {
$.each(data,function(i,value){
serie[i]=parseInt(value.sea_p);
serie1[i]=parseInt(value.deck_p);
});
option_p.series[0] = serie.reverse();
option_p.series[1] = serie1.reverse();
} else if (element == 'wave_height') {
$.each(data,function(i,value){
serie[i]=parseInt(value.wave_height);
});
option.series[0].data = serie.reverse();
} else if (element == 'visibility') {
$.each(data,function(i,value){
serie[i]=parseInt(value.visibility);
});
option.series[0].data = serie.reverse();
} else if (element == 'cloudheight') {
$.each(data,function(i,value){
serie[i]=parseInt(value.cloud_height);
});
option.series[0].data = serie.reverse();
}
switch(element){
case 'p' :
chart = new Highcharts.Chart(option_p);
break;
case 't_h':
chart = new Highcharts.Chart(option_th);
break;
case 'wind_speed':
chart = new Highcharts.Chart(option_wind_speed);
break;
default:
chart = new Highcharts.Chart(option);
}
/* old code, will be replaced with switch
if (element == 'p')
chart = new Highcharts.Chart(option_p);
else {
chart = new Highcharts.Chart(option);
}
*/
});
}
$( function(){
draw_curve(105,'t_h');
})//end of jquery function
![the chart][1]
thank you advance
The reason it doesn't work is because you didn't provide the values for y,m,d,h,minute for the Date.UTC(y,m,d,h,minute) in the pointStart property for your series. See working: http://jsfiddle.net/LzfM3/