I'm using Angular-Leaflet-directive and geojson for my markers and I'm having difficulties adding custom markers. I am able to style line/polygons using the style property but no such luck with adding custom icons
e.g. styling line/polygons
angular.extend($scope, {
geojson: {
data: data,
style: {
fillColor: "green",
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
}
}
});
e.g. attempting to add custom icons for my markers:
var myIcons = {
div_icon: {
type: 'div',
iconSize: [12, 12],
html: '<circle cx="10" cy="10" r="8" stroke="black" stroke-width="1" fill="green" />',
popupAnchor: [0, 0]
},
redPin: {
iconUrl: 'images/mapPinRed.png',
iconSize: [38, 95],
iconAnchor: [22, 94]
}
};
angular.extend($scope, {
geojson: {
data:data,
style: {icon: myIcons.redPin}
}
});
It turns out that in angular-leaflet-directive_v0.7.6 there is no "pointToLayer" for the geojson data, added "pointToLayer:geojson.pointToLayer"
eg angular-leaflet-directive
//...
geojson.options = {
style: geojson.style,
onEachFeature: onEachFeature,
pointToLayer:geojson.pointToLayer
};
It turns out that v0.8 has this feature
e.g. adding the icon
var myIcon = { iconUrl:'images/mapPinRed.png',
iconSize:[25, 25],
iconAnchor:[12, 0]})
};
angular.extend($scope, {
geojson: {
data:data,
style:
function (feature) {return {};},
pointToLayer: function(feature, latlng) {
return new L.marker(latlng, {icon: L.icon(myIcon);
},
onEachFeature: function (feature, layer) {
layer.bindPopup("number: " +feature.properties.something);
}
} //geojson
});
Related
In react-chartjs-2
In Line chart every grid should have different background colors.
Is this achievable with this library?
This is how LineChart should looks:
This is my Code/configuration:
const options = {
responsive: true,
scales: {
y: {
grid: {
backgroundColor: [
'rgba(36, 206, 0, 0.8)',
'rgba(255, 255, 0, .8)',
'rgba(255, 162, 0, 0.8)',
'rgba(36, 206, 0, 0.8)',
],
},
};
Thanks for reading.
You can use an inline plugin to achieve it:
var GradientBgPlugin = {
beforeDraw: function(chart, args, options) {
const ctx = chart.ctx;
const canvas = chart.canvas;
const chartArea = chart.chartArea;
// Chart background
var gradientBack = canvas.getContext("2d").createLinearGradient(0, 250, 0, 0);
gradientBack.addColorStop(0, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.16, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.17, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.25, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.26, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.5, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.51, "rgba(251,221,221,1)");
gradientBack.addColorStop(1, "rgba(251,221,221,1)");
ctx.fillStyle = gradientBack;
ctx.fillRect(chartArea.left, chartArea.bottom,
chartArea.right - chartArea.left, chartArea.top - chartArea.bottom);
}
};
Than just include it in your Chart options:
plugins: [GradientBgPlugin]
The result should be similar to this JSFiddle.
EDIT
For Reach Charts JS 2, you need small changes in setup. You define plugin this way:
const plugins = [{
beforeDraw: function(chart) {
const ctx = chart.ctx;
const canvas = chart.canvas;
const chartArea = chart.chartArea;
// Chart background
var gradientBack = canvas.getContext("2d").createLinearGradient(0, 250, 0, 0);
gradientBack.addColorStop(0, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.16, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.17, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.25, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.26, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.5, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.51, "rgba(251,221,221,1)");
gradientBack.addColorStop(1, "rgba(251,221,221,1)");
ctx.fillStyle = gradientBack;
ctx.fillRect(chartArea.left, chartArea.bottom,
chartArea.right - chartArea.left, chartArea.top - chartArea.bottom);
}
}];
Than you plug it this way:
<Line data={data} plugins={plugins} />
You can see it working fine on CodeSandbox here.
You can write a custom inline plugin, that draws the colors on the chart Area. In the options section you can put an object with all the sections you want, from where to where and which color they need to be
Example:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [100, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
plugins: {
backgrounds: {
hbars: [{
from: 28,
to: 100,
color: "rgb(195, 230, 195)"
},
{
from: 20,
to: 28,
color: "rgb(230, 220, 195)"
},
{
from: 0,
to: 20,
color: "rgb(230, 195, 195)"
}
]
}
}
},
plugins: [{
id: 'backgrounds',
beforeDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales: {
y
}
} = chart;
options.hbars.forEach((hBar) => {
ctx.save();
ctx.fillStyle = hBar.color;
ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
ctx.restore();
})
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.js"></script>
</body>
Detailed explanation can be found here: https://medium.com/#omi10859/alternative-background-lines-in-chartjs-a626ce4d3bcb
We can use annotaion plugin with chartjs to create custom elements.
we can use annotation plugin to do this
import annotationPlugin from "chartjs-plugin-annotation";
import {Chart} from 'chart.js';
Chart.register(annotationPlugin);
this code will add a box to our chart
{
type: 'box', #type of draw
drawTime: 'beforeDraw', #this will decide background or foreground
yMin: 5, #value min on y axis
yMax: 10, #value max on y axis
borderColor: 'rgb(242, 244, 248, 0.9)', #border color of the box
borderWidth: 1, #boarder width for box
backgroundColor: '#F2F4F8', #colour of the box
}
# add option while rendering
const options = {
plugins: {annotation: {annotations: background_annotation}
}
this code render this
Im using the e-charts libary for creating a bar chart for my data .
like so :
option.series = [
{
name: 'buy',
type: 'bar',
stack: 'one',
data: Object.values(chartData?.data || {}).map(elem => -elem.buy?.total),
color: colors.bought,
label: {
show: true,
position: "bottom",
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
// barWidth:this.data
},
{
name: 'sell',
type: 'bar',
stack: 'one',
data: Object.values(chartData?.data || {}).map(elem =>elem.sell?.total),
color: colors.sold,
label: {
show: true,
position: "top",
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
},
{
name: 'profite',
type: 'bar',
stack: 'two',
barGap: '-100%',
z: 100,
data: Object.values(chartData?.data || {}).map(elem => elem.sell?.profit),
color: colors.profit,
label: {
show: true,
position: "insideTop",
textBorderWidth: -1,
offset: [0, -20],
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
},
]
im trying to set a different width for each bar depending on the value of each bar .
on data property i get a list of numbers rendering .
When i try to add a barWidth property all i can do is change all of the bars in the same chrts like so for example:
barWidth: ${getBarWidth((Object.values(chartData?.data || {}).map((elem) => elem.sell?.amount)))}%
so i returne a different value of my data each time but it didnt changed each bar according to its value (either buy, sell and so on).
Thanks in adavance.
As you pointed out, barWidth sets the width of all the bars of a bar series. And I don't think there is a way to set the width of each bar in the same bar series.
What you should use instead is a custom series.
Custom series have a parameter called renderItem, where you write the render logic of the chart. It's where you'll be able to display custom shapes (custom sized bar in your case), using graphics.
Here is an example I found on their website, doing pretty much what you're looking for.
var container = document.getElementById('main');
var chart = echarts.init(container);
const colorList = [
'#4f81bd',
'#c0504d',
'#9bbb59',
'#604a7b',
'#948a54',
'#e46c0b'
];
const data = [
[10, 16, 3, 'A'],
[16, 18, 15, 'B'],
[18, 26, 12, 'C'],
[26, 32, 22, 'D'],
[32, 56, 7, 'E'],
[56, 62, 17, 'F']
].map(function (item, index) {
return {
value: item,
itemStyle: {
color: colorList[index]
}
};
});
chart.setOption({
title: {
text: 'Profit',
left: 'center'
},
tooltip: {},
xAxis: {
scale: true
},
yAxis: {},
series: [
{
type: 'custom',
renderItem: function (params, api) {
var yValue = api.value(2);
var start = api.coord([api.value(0), yValue]);
var size = api.size([api.value(1) - api.value(0), yValue]);
var style = api.style();
return {
type: 'rect',
shape: {
x: start[0],
y: start[1],
width: size[0],
height: size[1]
},
style: style
};
},
label: {
show: true,
position: 'top'
},
dimensions: ['from', 'to', 'profit'],
encode: {
x: [0, 1],
y: 2,
tooltip: [0, 1, 2],
itemName: 3
},
data: data
}
]
});
#main {
width: 600px;
height: 400px;
}
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.2/echarts.min.js"></script>
<div id="main"></div>
</body>
</html>
I am using chartjs-plugin-annotation in chartJs with ReactJs. But in box annotation is there a way how can I resize the box so I can expend the min, max value of the annotation.
My option code: `
options: {
scales: {
y: {
beginAtZero: true
}
},
plugins: {
autocolors: false,
annotation: {
annotations: {
box1: {
type: "box",
xMin: 1,
xMax: 2,
yMin: 5,
yMax: 10,
backgroundColor: "rgba(255, 99, 132, 0.25)"
}
}
}
}
}
`
Here is my code sandbox ReactJs-ChartJs
Yes, you can dive into the options part of your chart object, adjust the config for your annotation and then call chart.update() this will update the annotation.
Example:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
}]
},
options: {
plugins: {
annotation: {
annotations: {
box1: {
type: "box",
xMin: 1,
xMax: 2,
yMin: 5,
yMax: 10,
backgroundColor: "rgba(255, 99, 132, 0.25)"
}
}
}
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
document.getElementById("tt").addEventListener("click", () => {
chart.options.plugins.annotation.annotations.box1.yMax = 16;
chart.update();
});
document.getElementById("rr").addEventListener("click", () => {
chart.options.plugins.annotation.annotations.box1.yMax = 8;
chart.update();
});
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<button id="tt">Update annotation to 16</button>
<button id="rr">Update annotation to 8</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-annotation/1.0.2/chartjs-plugin-annotation.js"></script>
</body>
I'm trying to code a modified version of this example.
Using vanilla Javascript all is working fine, but now I'm trying to move it to React and the popup doesn't follow the map when I zoom in or zoom out the map. I suppose that the popup is not linked to the map overlay, but it's totally disconnected from it and this should be the problem, but I don't know how to fix it:
This is my code:
import 'ol/ol.css';
import React, { Component } from "react";
import ReactDOM from 'react-dom';
import Map from 'ol/Map';
import View from 'ol/View';
import Overlay from 'ol/Overlay';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { OSM, Vector as VectorSource } from 'ol/source';
import { Circle as CircleStyle, Icon, Fill, Stroke, Style, Text } from 'ol/style';
import GeoJSON from 'ol/format/GeoJSON';
import * as olExtent from 'ol/extent';
import $ from 'jquery';
import 'bootstrap';
import markerLogo from './marker.png';
class PublicMap extends Component {
constructor(props) {
super(props);
var shapeDisciplinare = this.props.geoJson;
var iconStyle = new Style({
image: new Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: markerLogo
}),
text: new Text({
font: '12px Calibri,sans-serif',
fill: new Fill({ color: '#000' }),
stroke: new Stroke({
color: '#fff', width: 2
})
})
});
var getStyles = function (feature) {
var myStyle = {
'Point': iconStyle,
'Polygon': new Style({
stroke: new Stroke({
color: 'blue',
width: 3
}),
fill: new Fill({
color: 'rgba(0, 0, 255, 0.1)'
}),
text: new Text({
font: '12px Calibri,sans-serif',
fill: new Fill({ color: '#000' }),
stroke: new Stroke({
color: '#fff', width: 2
}),
text: feature.getProperties().denominazione
})
})
};
return [myStyle[feature.getGeometry().getType()]];
};
var raster = new TileLayer({
source: new OSM()
});
var source = new VectorSource();
var vector = new VectorLayer({
source: source,
style: new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new Stroke({
color: '#ffcc33',
width: 2
}),
image: new CircleStyle({
radius: 7,
fill: new Fill({
color: '#ffcc33'
})
})
})
});
vector.setZIndex(1);
this.olmap = new Map({
layers: [raster, vector],
target: null,
view: new View({
center: [-11000000, 4600000],
zoom: 4
})
});
var reader = new GeoJSON({
defaultDataProjection: 'EPSG:3857',
Projection: 'EPSG:3857'
});
var projector = {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
};
let shapeDisciplinareJson = JSON.parse(shapeDisciplinare);
var vectorSource = new VectorSource({
features: reader.readFeatures(shapeDisciplinareJson, projector)
});
var vectorLayer = new VectorLayer({
source: vectorSource,
style: getStyles
});
this.state = { vs: vectorSource, vl: vectorLayer };
}
componentDidMount() {
this.olmap.setTarget("map");
var extent = olExtent.createEmpty();
extent = olExtent.extend(extent, this.state.vs.getExtent());
this.olmap.addLayer(this.state.vl);
this.olmap.getView().fit(extent, this.olmap.getSize());
this.olmap.getView().setZoom(8);
var element = document.getElementById('popup');
this.popup = new Overlay({
element: ReactDOM.findDOMNode(this).querySelector('#popup'),
positioning: 'bottom-center',
stopEvent: false,
offset: [0, -50]
});
// display popup on click
this.olmap.on('click', (evt) => {
var feature = this.olmap.forEachFeatureAtPixel(evt.pixel,
(feature) => {
return feature;
});
if (feature) {
var coordinates = feature.getGeometry().getCoordinates();
//if lenght is 2, then is a gps location, otherwise a shape
if (coordinates.length === 2) {
this.popup.setOffset([0, -50]);
this.popup.setPosition(coordinates);
} else {
this.popup.setOffset([0, 0]);
this.popup.setPosition(evt.coordinate);
}
this.olmap.addOverlay(this.popup);
$(element).popover({
'placement': 'top',
'html': true,
'content': feature.getProperties().denominazione
});
$(element).attr('data-content', feature.getProperties().denominazione);
$(element).popover('show');
} else {
$(element).popover('hide');
}
});
// change mouse cursor when over marker
this.olmap.on('pointermove', (e) => {
if (e.dragging) {
$(element).popover('hide');
return;
}
var pixel = this.olmap.getEventPixel(e.originalEvent);
var hit = this.olmap.hasFeatureAtPixel(pixel);
this.olmap.getTargetElement().style.cursor = hit ? 'pointer' : '';
});
}
componentWillUnmount() {
this.map.setTarget(null);
}
render() {
return (
<div id="map" style={{ width: "100%", height: "360px" }}>
<div id="popup"></div>
</div>
);
}
}
export default PublicMap;
I wonder how I should go about having better animations when adding points to a area plot. In regular highcharts this is done pretty smooth but using highcharts-ng it rerenders a huge chunk of the chart.
I have two fiddels that shows the issue. Maby there is a simple way to solve this ?
Highcharts-ng
http://jsfiddle.net/Cp73s/3399/
var myapp = angular.module('myapp', ["highcharts-ng"]);
myapp.controller('myctrl', function ($scope) {
$scope.addPoints = function () {
var seriesArray = $scope.highchartsNG.series
var rndIdx = Math.floor(Math.random() *10+7);
$scope.highchartsNG.series[0].data.push(rndIdx);
};
$scope.highchartsNG = {
options: {
chart: {
type: 'area'
},
plotOptions: {
area: {
fillOpacity: 0.15,
dataLabels: {
allowOverlap: true,
enabled: true,
padding: 0,
style: {
fontSize: '25px'
}
},
enableMouseTracking: true
}
},
},
series: [{
data: [10, 15, 12, 8, 7]
}]
}
});
Regular-highcharts
http://jsfiddle.net/m8Lavyrc/3/
$(function () {
$('#container').highcharts({
chart: {
type: 'area'
},
plotOptions: {
area: {
fillOpacity: 0.15,
dataLabels: {
allowOverlap: true,
enabled: true,
padding: 0,
style: {
fontSize: '25px'
}
},
enableMouseTracking: true
}
},
series: [{
data: [10, 15, 12, 8, 7]
}]
});
// the button action
var i = 0;
$('#button').click(function () {
var chart = $('#container').highcharts();
chart.series[0].addPoint(Math.floor(Math.random() *10+7));
});
});
Tnx