Here is documentation for Icon Layer https://deck.gl/docs/api-reference/layers/icon-layer
I want to use this IconLayer to display markers on the map.
I used this like below.
import
import { IconLayer } from "#deck.gl/layers";
Icon mapping
const ICON__MAPPING = {
marker: { x: 0, y: 0, width: 128, height: 128, mask: false }
};
Icon layer
const iconLayer = new IconLayer({
id: "icon-layer",
data: [
{
name: "Colma (COLM)",
address: "365 D Street, Colma CA 94014",
exits: 4214,
coordinates: [76.993894, 31.781929]
}
],
pickable: true,
// iconAtlas and iconMapping are required
// getIcon: return a string
iconAtlas: "https://img.icons8.com/dusk/64/000000/user-location.png",
getIcon: (d) => d.name,
iconMapping: ICON__MAPPING,
sizeScale: 15,
getPosition: (d) => d.coordinates,
getSize: (d) => 55,
getColor: (d) => [Math.sqrt(d.exits), 140, 0]
});
I used everything as documented. I am not doing any experiment. Still icon is not visible on the map.
Live Demo
https://codesandbox.io/s/reverent-framework-uepze?file=/src/App.js
The iconmapping name must match what you do in getIcon, i.e.: "Colma (COLM)" !== "marker"
Related
I managed to get the real time example to work:
https://jsfiddle.net/TradingView/yozeu6k1/
I tried to get a real time histogram underneath, as the usual volume indicator and the behavior is random.
A snapshot of the chart:
enter image description here
As we can see the starting point of those bars differ one from another.
Series definition:
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: 'volume',
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0,
}
});
Update:
volumeSeries.update({
time: data.time,
value: data.volume
});
Can anyone point me to an example in order to get a candlestick chart with a volume indicator to work? Both updating in real time.
I got it to work, basically the issue was that the histogram understands negative values as a down facing bar, so in order to show a volume indicator we have to show the absolute value of the volume and change the color.
A working example at: https://jsfiddle.net/rondolfo/0zg7u9tv/57/
//colours
var green = 'rgb(38,166,154)';
var red = 'rgb(255,82,82)';
var black = '#000000';
var white = 'rgba(255, 255, 255, 0.9)';
var grey = 'rgba(42, 46, 57, 0.5)';
// chart definition
var chart = LightweightCharts.createChart(document.body, {
width: 800,
height: 400,
layout: {
backgroundColor: black,
textColor: white,
},
grid: {
vertLines: {
visible: false,
},
horzLines: {
color: grey,
},
},
crosshair: {
mode: LightweightCharts.CrosshairMode.Normal,
}
});
chart.applyOptions({
timeScale: {
borderVisible: false,
borderColor: '#fff000',
visible: true,
timeVisible: true,
minBarSpacing: 0.0,
}
});
const candleStickSeries = chart.addCandlestickSeries({
upColor: green,
downColor: red,
wickUpColor: green,
wickDownColor: red,
borderVisible: false,
priceLineVisible: false,
});
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: 'volume',
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0.02,
}
});
//end chart definition
//data loading
jQuery.ajaxSetup({
async: false
});
var url = 'https://raw.githubusercontent.com/AnAlgoTrader/TradingView.LightWeightCharts.Example/main/InputData/prices.json';
var data = [];
$.get(url, function(result) {
data = JSON.parse(result);
});
//end data loading
//real time updates
var index = 0;
setInterval(function() {
if (index > data.length) return;
var item = data[index];
candleStickSeries.update({
time: item.time,
open: item.open,
high: item.high,
low: item.low,
close: item.close
});
var volumeColour = item.volume < 0 ? red : green;
volumeSeries.update({
time: item.time,
value: Math.abs(item.volume),
color: volumeColour
});
index++;
}, 1000);
I've recently started working with D3 and I am moving all my existing charts over from Chartjs and so far my attempts have been successful. There is this one chart however that I am unable to produce exactly the same way in D3.
So with Chartjs, there's properties built in to the library that we can use to set the colors for values above and below a certain point on a Line chart. Here's what I had used to get the intended chart with Chartjs:
...config,
fill: {
above: '#4E4AFF20',
below: '#FF515114',
target: 'origin'
},
...config
And this is what the chart in Chartjs ended up looking like:
But D3 doesn't seem to have such a thing as far as I can tell. There's only gradients. So here's what I was able to build in D3:
As you can see, this looks way different from what I had earlier with Chartjs. Also notice how the gradient exists in both the line and the colored area underneath. I know it's there because I added it but that's not what I want and everywhere I look, that's the only way people are doing it. I have done countless attempts to fix this to no avail hence now I'm here asking for your help. Here's the D3 code I have right now:
import * as d3 from 'd3';
import { useEffect, useRef } from 'react';
interface Data {
x: number;
y: number;
}
const width = 350;
const height = 117;
const zeroPoint = 0;
const data: Data[] = [
{ x: 0, y: -20 },
{ x: 10, y: -20 },
{ x: 20, y: -20 },
{ x: 40, y: -20 },
{ x: 50, y: -20 },
{ x: 60, y: -20 },
{ x: 70, y: -20 },
{ x: 80, y: 0 },
{ x: 90, y: 20 },
{ x: 100, y: 20 },
{ x: 110, y: 20 },
{ x: 120, y: 20 },
{ x: 130, y: 20 },
{ x: 140, y: 20 },
{ x: 150, y: 20 }
];
export const Chart: React.FC = () => {
const ref = useRef<SVGSVGElement>(null);
const generateLinePath = (
element: d3.Selection<SVGSVGElement, unknown, null, undefined>,
data: Data[],
xScale: d3.ScaleLinear<number, number>,
yScale: d3.ScaleLinear<number, number>
) => {
const lineGenerator = d3
.line<Data>()
.x(d => xScale(d.x))
.y(d => yScale(d.y));
element.append('path').attr('d', lineGenerator(data));
};
const drawZeroLine = (element: d3.Selection<SVGSVGElement, unknown, null, undefined>, yScale: d3.ScaleLinear<number, number>) => {
element
.append('line')
.attr('x1', '0')
.attr('y1', yScale(zeroPoint))
.attr('x2', width)
.attr('y2', yScale(zeroPoint))
.attr('stroke', '#c4c4c4');
};
const createChart = (data: Data[]) => {
const svg = d3.select(ref.current!).attr('viewBox', `0 0 ${width} ${height}`);
svg.selectAll('*').remove();
const [minX, maxX] = d3.extent(data, d => d.x);
const [minY, maxY] = d3.extent(data, d => d.y);
const xScale = d3.scaleLinear().domain([minX!, maxX!]).range([0, width]);
const yScale = d3
.scaleLinear()
.domain([minY!, maxY!])
.range([height, 0]);
svg
.append('linearGradient')
.attr('id', 'line-gradient')
.attr('gradientUnits', 'userSpaceOnUse')
.attr('x1', 0)
.attr('x2', width)
.selectAll('stop')
.data(data)
.join('stop')
.attr('offset', d => xScale(d.x) / width)
.attr('stop-color', d => (d.y < zeroPoint ? '#FF5151' : '#4E4AFF'));
svg
.append('linearGradient')
.attr('id', 'area-gradient')
.attr('gradientUnits', 'userSpaceOnUse')
.attr('x1', xScale(data[0].x))
.attr('x2', xScale(data[data.length - 1].x))
.selectAll('stop')
.data([
{ color: '#FF515110', offset: '0%' },
{ color: '#4E4AFF20', offset: '100%' }
])
.enter()
.append('stop')
.attr('offset', function (d) {
return d.offset;
})
.attr('stop-color', function (d) {
return d.color;
});
svg.attr('stroke', 'url(#line-gradient)').attr('fill', 'url(#area-gradient)');
generateLinePath(svg, data, xScale, yScale);
drawZeroLine(svg, yScale);
};
useEffect(() => {
createChart(data);
}, []);
return <svg ref={ref} />;
};
So there's two problems I am looking to get solved with your help. The more important one is to give different colors to areas under and above the zero line in D3 the way I was able to do with Chartjs and the other one is moving away from gradients and get solid colors without any smooth transitions on both the line and the colored areas underneath.
Alright I managed to recreate the same chart in D3 using a workaround.
So it's not as straightforward as it's in Chartjs but it works pretty well. The idea is to create polygons under and over the line using the same data used to generate the line.
So my chart works like this. The grey line is a straight zero line and the values below zero go under that line with a red color and the ones above are purple. And here's what the Chart data looks like:
data = [
{ x: 0, y: 0 },
{ x: 1, y: 1 },
...
]
Anyways, here's the steps
Generate the scales
const [minX, maxX] = d3.extent(data, d => d.x);
const [minY, maxY] = d3.extent(data, d => d.y);
const xScale = d3.scaleLinear().domain([minX, maxX]).range([0, width]);
const yScale = d3.scaleLinear().domain([minY, maxY]).range([height, 0]);
Generate the line chart using D3's line() function. And don't give any stroke to the generated line.
const lineGenerator = d3.line().x(d => xScale(d.x)).y(d => yScale(d.y));
element.append('path').attr('d', lineGenerator(data));
Add a red SVG polygon that starts from the left side at zero line, then goes to the left bottom, then to where the value starts becoming negative and then finally to where the line reaches the zero line again.
svg.append('polygon').attr(
'points',
`
${xScale(minX - 1)},${yScale(0)} // top left point
${xScale(minX - 1)},${yScale(minY)} // bottom left point
${xScale(data[indexWhereRedPointStartsBecomingPositive].x)},${yScale(data[indexWhereRedPointStartsBecomingPositive].y)} // bottom right point
${xScale(data[indexWhereXReachesZeroLine].x)},${yScale(0)} // top right point
`
)
.attr('fill', 'lightRed')
.attr('stroke', 'darkRed');
Notice how we gave the red stroke to the polygon? That's the reason why we got rid of the stroke from the line and gave it here instead. This is because we need two separate colors (red for below and purple for above) for the chart. The reason why we do minX - 1 is because the stroke is applied to all four sides of the polygon and we want to hide it from the left side so we subtract 1px from the left.
Add another purple SVG polygon that starts from the left side at zero line (where the purple area starts somewhere in the middle), then goes all the way to the right end of the chart and then goes up to the top.
svg.append('polygon').attr(
'points',
`
${xScale(data[indexWhereValueStartsGoingPositive].x)},${yScale(0)}
${width + 1},${yScale(data[data.length - 1].y)}
${width + 1},${yScale(0)}
`
)
.attr('fill', 'lightPurple')
.attr('stroke', 'darkPurple');
Here we do width + 1 to hide the stroke of this purple polygon on the right side the same way we did minX - 1 with the left side of the red box.
So in conclusion, instead of giving stroke to the line generated using d3.line(), give strokes to the two polygons created using the same data that was used to generate the line chart and create the polygons 1px larger than the chart data so the strokes don't appear on the left and right side of the charts.
That's quite a lot I know but I couldn't think of any other way to get the chart to look like this. Anyways, I hope this helps anyone else experiencing a similar problem.
I'm using some custom attributes while I'm creating my objects. For example in this case "name" and "icon":
$scope.addRoundRect = function () {
var coord = getRandomLeftTop();
var roundrect = (new fabric.Rect({
left: coord.left,
top: coord.top,
fill: '#' + getRandomColor(),
width: 250,
height: 250,
opacity: 1,
scaleX: 1,
scaleY: 1,
angle: 0,
rx: 10,
ry: 10,
strokeWidth: 0,
name: "Rounded Rectangle",
icon: "crop-square"
}));
canvas.add(roundrect).setActiveObject(roundrect);
};
This is my copy/paste function. As you can see I have already tried to paste the relevant attributes – bu I think that they are simply not cloned with the object:
function copy() {
canvas.getActiveObject().clone(function (cloned) {
_clipboard = cloned;
});
}
function paste() {
_clipboard.clone(function (clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
name: clonedObj.name,
icon: clonedObj.icon,
});
if (clonedObj.type === 'activeSelection') {
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
To make it short: is there a way to clone and paste also this attributes without having to modify the source (ie. impleneting a full fledged custom attribute in the JSO serialization)?
var canvas = new fabric.Canvas('c');
var roundrect = new fabric.Rect({
left: 50,
top: 30,
fill: 'blue',
width: 250,
height: 250,
opacity: 1,
scaleX: 1,
scaleY: 1,
angle: 0,
rx: 10,
ry: 10,
strokeWidth: 0,
name: "Rounded Rectangle",
icon: "crop-square"
});
canvas.add(roundrect).setActiveObject(roundrect);
var customProperties = 'name icon'.split(' ');
function copy() {
canvas.getActiveObject().clone(function(cloned) {
console.log(cloned);
_clipboard = cloned;
}, customProperties);
}
function paste() {
// clone again, so you can do multiple copies.
_clipboard.clone(function(clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
// active selection needs a reference to the canvas.
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
// this should solve the unselectability
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
console.log(clonedObj);
_clipboard = clonedObj;
},customProperties);
}
canvas {
border: blue dotted 2px;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<button onclick='copy()'>copy</button>
<button onclick='paste()'>paste</button><br>
<canvas id="c" width="400" height="400"></canvas>
object.clone accepts callback function and any additional property you want to include as another parameter. You can send your name and icon as properties to include.
And in paste you no need to clone that object if you are doing so, make sure there also send you are including your additional properties.
I'm trying to include a JointJS diagram in my React+Flux project.
I started from an existing demo available there.
My idea is to embed the diagram in an higher level component that will be reused inside my project.
The structure that I came up with is the following:
index.html
...
<body>
<section id="mySec"></section>
...
app.js
...
ReactDOM.render(
<JointJSDiagram id="1"/>,
document.getElementById('mySec')
);
JointJSDiagram.react.js
...
var JointJSDiagramStore = require('../stores/JointJSDiagramStore');
class JointJSDiagram extends React.Component {
...
componentDidMount() {
var el = this.refs[this.props.placeHolder];
document.addEventListener("DOMContentLoaded", function(elt){
return function(){JointJSDiagramStore.buildDiagram(elt)};
}(el), false);
}
...
render() {
return (<div ref={this.props.placeHolder}/>);
}
...
}
module.exports = JointJSDiagram;
JointJSDiagramStore.js
...
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var _graph = new joint.dia.Graph();
var _paper = new joint.dia.Paper({
width: 600,
height: 200,
model: _graph,
gridSize: 1
});
var JointJSDiagramStore = assign({}, EventEmitter.prototype, {
...
buildDiagram: function(el) {
_paper.el = el;
// In here I used the code from: http://www.jointjs.com/demos/fsa
function state(x, y, label) {
var cell = new joint.shapes.fsa.State({
position: { x: x, y: y },
size: { width: 60, height: 60 },
attrs: {
...
...
...
link(star, block, 'other', [{x: 650, y: 290}]);
link(star, code, '/', [{x: 490, y: 310}]);
link(line, line, 'other', [{x: 115,y: 100}, {x: 250, y: 50}]);
link(block, block, 'other', [{x: 485,y: 140}, {x: 620, y: 90}]);
link(code, code, 'other', [{x: 180,y: 500}, {x: 305, y: 450}]);
},
...
});
...
module.exports = JointJSDiagramStore;
The problem is that nothing is visualized except for some (7) warnings stating:
Warning: ReactDOMComponent: Do not access .getDOMNode() of a DOM node;
instead, use the node directly. This DOM node was rendered by
JointJSDiagram.
UPDATE
If I explicitly use the id instead of refs like this:
JointJSDiagramStore.js
...
componentDidMount() {
var el = document.getElementById(this.props.placeHolder);
document.addEventListener("DOMContentLoaded", function(elt){
return function(){JointJSDiagramStore.buildDiagram(elt)};
}(el), false);
JointJSDiagramStore.addChangeListener(this._onChange);
}
...
render() {
return (<div id={this.props.placeHolder}/>);
}
...
I don't receive Warnings anymore, but nothing is still displayed on the placeholder div.
This quick test worked for me. I'm using react 0.14.3
class Graph extends React.Component {
constructor(props) {
super(props);
this.graph = new joint.dia.Graph();
}
componentDidMount() {
this.paper = new joint.dia.Paper({
el: ReactDOM.findDOMNode(this.refs.placeholder),
width: 600,
height: 200,
model: this.graph,
gridSize: 1
});
const rect = new joint.shapes.basic.Rect({
position: { x: 100, y: 30 },
size: { width: 100, height: 30 },
attrs: {
rect: { fill: 'blue' },
text: { text: 'my box', fill: 'white' }
}
});
const rect2 = rect.clone();
rect2.translate(300);
const link = new joint.dia.Link({
source: { id: rect.id },
target: { id: rect2.id }
});
this.graph.addCells([rect, rect2, link]);
}
render() {
return <div ref="placeholder" ></div>;
}
}
I have a question related the chart export.
Please see Jsfiddle here
I added a text label using chart.renderer.text on the Yaxis for the latest value of series.
If I directly click button "Export Image". There is no problem, the label can be displayed. I'm using the following way to export image. draw_labels() is a function to draw yaxis label.
$("#b").click(function () {
chart.exportChart(null, {
chart: {
backgroundColor: '#FFFFFF',
width: 972,
height: 480,
events: {
load: function () {
draw_labels(this);
}
}
}
});
});
The problem is after I clicked range selector or change Xaxis range. When I try to export the
chart to image, there is no labels are drawn. The following is the complete code.
The following is the complete code:
$(function () {
var chart;
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-c.json&callback=?', function (data) {
chart = new Highcharts.StockChart({
chart: {
renderTo: 'container',
events: {
load: function () {
draw_labels(this);
$("#b").click(function () {
chart.exportChart(null, {
chart: {
backgroundColor: '#FFFFFF',
width: 972,
height: 480,
events: {
load: function () {
draw_labels(this);
}
}
}
});
});
}
}
},
series: [{
name: 'AAPL',
id: 'test',
data: data,
tooltip: {
valueDecimals: 2
}
}],
navigator: {
enabled: false
},
yAxis: {
tickWidth: 0,
id: 'value_axis',
type: 'linear',
gridLineColor: '#EEE',
lineColor: '#D0CDC9',
lineWidth: 0,
minorTickInterval: null,
opposite: true,
offset: 0
},
xAxis: {
events: {
afterSetExtremes: function (e) {
console.log('test');
$('[id="test_text"]').remove();
draw_labels(chart);
}
}
}
});
});
function draw_labels(chart) {
$(chart.series).each(function (i, serie) {
var s_id = serie.options.id;
var temp_id = s_id;
var point = serie.points[serie.points.length - 1];
if (point) {
var pre, post;
if (point.y) {
var last_value_dis = (point.y).toFixed(1);
yaxis_name = 'value_axis';
//Get Yaxis position
var y_axis = chart.get(yaxis_name);
offsite_yaxis = 0;
element_text = chart.renderer.text(
//the text to render
'<span style="font-size:10px;font-weight:bold;color:' + serie.color + ';">' + last_value_dis + '</span>',
//the 'x' position
y_axis.width + y_axis.offset,
//the 'y' position
chart.plotTop + point.plotY + 3).attr({
id: temp_id + '_text',
zIndex: 999
}).add();
}
}
});
}
});
Here, I have fixed it for you. Here is a saved image:
Following changes have been done:
Added a redraw event to your exportchart
redraw: function () {
$("#test_text").remove() ;
draw_labels(this);
}
Changed this line in afterSetExtremes
$('[id="test_text"]').remove();
to
$("#test_text").remove() ;
Earlier one was not working as expected, so I had to change it.
Problem with disappearing text is related with id, when I removed it, label appears. But then I came across second issue, wrong y position. So i declare global variable, then when you call your function, set position of label, and use in chart exporting this variable. As a result label is exported correct.
http://jsfiddle.net/UGbpJ/11/