【发布时间】:2020-06-18 01:48:57
【问题描述】:
我正在尝试使用此 API
https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=IBM&interval=5min&apikey=demo
使用 d3js 烛台图,我设法使用这个 index.html 文件运行了一个示例,IDK 为什么它不能在 stackoverflow 提供的代码段上运行,也不能在 codepen 上运行,但它在本地环境甚至生产环境中运行。
这是文件。
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-ease.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<script src="https://d3js.org/d3-timer.v1.min.js"></script>
<script src="https://d3js.org/d3-transition.v1.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<style>
.label {
fill: #fff;
font-family: sans-serif;
font-size: 10px;
line-height : 1;
vertical-align: middle;
}
text {
fill : #777;
}
rect {
shape-rendering: crispEdges;
stroke-width : 1px;
}
line {
shape-rendering: crispEdges;
stroke-width: 1px;
}
line.focusLine {
stroke: #777;
stroke-linecap: butt;
}
.domain {
stroke: #777;
stroke-width : 1px;
}
</style>
<script>
(function() {
var jQuery;
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.4.2') {
var script_tag = document.createElement('script');
script_tag.setAttribute("type","text/javascript");
script_tag.setAttribute("src",
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js");
if (script_tag.readyState) {
script_tag.onreadystatechange = function () {
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
} else {
script_tag.onload = scriptLoadHandler;
}
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} else {
jQuery = window.jQuery;
main();
}
function scriptLoadHandler() {
jQuery = window.jQuery.noConflict(true);
main();
}
/******** Our main function ********/
function main() {
jQuery(document).ready(function($) {
// We can use jQuery 1.4.2 here
// Widgets starts here
var json;
// Get data from API
const getJSON = async url => {
try {
const response = await fetch(url);
if(!response.ok) // check if response worked (no 404 errors etc...)
throw new Error(response.statusText);
const data = await response.json(); // get JSON from the response
return data; // returns a promise, which resolves to this data value
} catch(error) {
return error;
}
}
console.log("Fetching data...");
getJSON("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=IBM&interval=5min&apikey=demo").then(data => {
console.log(data);
var json = data;
}).catch(error => {
console.error(error);
});
console.log(json);
// Chart starts here
var totalWidth = window.innerWidth;
var totalHeight = window.innerHeight;
var margin = { top : 10, left : 50, bottom : 30 , right : 50 }
var width = totalWidth - margin.left - margin.right;
var height = totalHeight - margin.top - margin.bottom;
window.addEventListener( "resize", function(e) {
totalWidth = window.innerWidth;
totalHeight = window.innerHeight;
width = totalWidth - margin.left - margin.right;
height = totalHeight - margin.top - margin.bottom;
redrawChart()
});
// DATA STUFF
var formatDecimal = d3.format(',.2f');
var parseDate = d3.timeParse("%Y%m%d"); // 20150630
var outputFormat = d3.timeFormat("%d %b %Y") // 30 June 2015
var dataLoaded = null;
var dataModelJSON = function( d ) {
return {
date : parseDate(+d.date),
open : +d.open,
high : +d.high,
low : +d.low,
close : +d.close,
volume: +d.volume,
openInt : +d.openInt
}
};
var data = json.map( dataModelJSON );
function setData( data ) {
dataLoaded = data;
}
function redrawChart() {
if( dataLoaded ) {
d3.select("#candle-chart").remove();
prepareForBuild(dataLoaded);
buildChart(dataLoaded);
}
}
var xScale, xLabels, xAxis, yIsLinear, yDomain, yRange, yScale, yAxis;
function prepareForBuild( data ) {
xScale = d3.scaleBand()
.domain( data.map( function(d) { return d.date ; } ) )
.range( [ 0 , width ] )
.paddingInner(0.2)
.paddingOuter(0)
.align(0.5)
xLabels = xScale.domain().filter( function(d, i) {
if( i === data.length-1) return d;
var next;
if( data[i+1] ) {
next = data[i+1].date;
} else {
return false;
}
var monthA = d.getMonth();
var monthB = next.getMonth();
return (monthB > monthA ? d : ((monthB === 0 && monthA===11) ? d : false));
});
xAxis = d3.axisBottom( xScale )
.tickFormat( outputFormat )
.tickValues( xLabels );
yIsLinear = true;
yDomain = [d3.min(data, d => d.low), d3.max(data, d => d.high) ];
yRange = [ height, 0 ];
yScale = d3.scaleLinear().domain( yDomain ).range( yRange ).nice(5);
yAxis = d3.axisLeft( yScale )
.ticks(5)
.tickSizeInner(-width)
.tickFormat( formatDecimal );
}
function buildChart( data ) {
var svg = d3.select('body').append('svg')
.attr( "id", "candle-chart")
.attr( "width", totalWidth )
.attr( "height", totalHeight );
var mainGroup = svg.append("g")
.attr("id", "mainGroup")
.attr("transform", "translate( " + margin.left + ", " + margin.top + ")");
var xAxisGroup = mainGroup.append("g")
.attr("id", "xAxis")
.attr( "class" , "axis" )
.attr( "transform", "translate( "+0+","+ height + ")" )
.call( customXAxis );
function customXAxis(g) {
g.call( xAxis );
g.select(".domain").attrs({
})
g.selectAll(".tick line")
.attr("y1", -height)
.attr("y2", 0)
.attr("stroke", "#777")
.attr("stroke-dasharray", "3,2");
}
var yAxisGroup = mainGroup.append("g")
.attr("id", "yAxis")
.attr( "class" , "axis" )
.call( customYAxis );
function customYAxis( g ) {
g.call( yAxis );
g.selectAll(".tick line")
.attr("x1", 0)
.attr("x2", width )
.attr("stroke", "#777")
.attr("stroke-dasharray", "3,2");
g.selectAll(".tick:first-of-type line").remove()
g.selectAll(".tick text")
.attr("x", -9);
}
var eventGroup = mainGroup.append("g")
.attr('id' , 'event-overlay');
var crosshair = eventGroup.append("g")
.attr("id", "crosshair");
var eventRect = eventGroup.append('rect');
var canvasGroup = eventGroup.append("g")
.attr("id", "circleGroup");
// http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript
function getTextWidth(text, font) {
var textWidth = 0;
var context = document.createElement("canvas").getContext("2d");
context.font = font;
textWidth = context.measureText(text).width;
return textWidth;
}
var crosshairSettings = {
xLabelTextOffset : height+12,
yLabelTextOffset : -9,
ylabelWidth : getTextWidth( formatDecimal(yDomain[1]), "10px sans-serif" )+2,
xlabelWidth : getTextWidth( "30 September 2000", "10px sans-serif"),
labelHeight: 14,
labelColor : "#aaa",
labelStrokeColor : "none",
labelStrokeWidth : "0.5px"
}
crosshair.append("line")
.attrs({
"id" : "focusLineX",
"class": "focusLine",
});
crosshair.append("line")
.attrs({
"id" : "focusLineY",
"class": "focusLine",
});
crosshair.append("rect") // x label bg
.attrs({
"id" : "focusLineXLabelBackground",
"class": "focusLineLabelBackground",
"fill" : crosshairSettings.labelColor,
"stroke" : crosshairSettings.labelStrokeColor,
"stroke-width" : crosshairSettings.labelStrokeWidth,
"width" : crosshairSettings.xlabelWidth,
"height" : crosshairSettings.labelHeight,
});
crosshair.append("text")
.attrs({
"id" : "focusLineXLabel",
"class" : "label",
"text-anchor" : "middle",
"alignment-baseline": "central"
});
var ylabel = crosshair.append("g").attr("id", "yLabelGroup");
ylabel.append("rect")
.attrs({
"id" : "focusLineYLabelBackground",
"class": "focusLineLabelBackground",
"fill" : crosshairSettings.labelColor,
"stroke" : crosshairSettings.labelStrokeColor,
"stroke-width" : crosshairSettings.labelStrokeWidth,
"width" : crosshairSettings.ylabelWidth,
"height" : crosshairSettings.labelHeight,
});
ylabel.append("text")
.attrs({
"id" : "focusLineYLabel",
"class" : "label",
"text-anchor" : "end",
"alignment-baseline": "central"
});
setCrosshair( width, 0);
var candleSettings = {
stroke : "black",
up : "#aaa",
down : "#d30000",
hover : "#ffffff",
lineMode : false
};
canvasGroup.selectAll("line")
.data( data )
.enter()
.append('line')
.attr( "x1", function( d, i) { return xScale( d.date ) + xScale.bandwidth()*0.5 } )
.attr( "y1", function( d ) { return yScale( d['high'] ) } )
.attr( "x2", function( d, i) { return xScale( d.date ) + xScale.bandwidth()*0.5 } )
.attr( "y2", function( d ) { return yScale( d['low'] ) } )
.style("stroke", candleSettings.stroke)
.style("stroke-width", "1px")
.style( "opacity", 1 )
if(xScale.bandwidth() > 1 ) {
candleSettings.lineMode = false;
canvasGroup.selectAll("rect")
.data( data )
.enter()
.append('rect')
.attrs({
x: function(d, i) {
return xScale( d.date );
},
y: function(d, i) {
return yScale( Math.max(d.close, d.open) )
},
width: xScale.bandwidth(),
height: function(d, i) {
var max = yScale(Math.min(d.close, d.open));
var min = yScale(Math.max(d.close, d.open));
var diff = max - min ;
return diff || 0.1;
},
})
.styles({
"fill" : function( d ) {
return d.close > d.open ? candleSettings.up : candleSettings.down;
},
"stroke" : candleSettings.stroke
})
} else {
candleSettings.lineMode = true
}
var els = candleSettings.lineMode ? canvasGroup.selectAll('line') : canvasGroup.selectAll('rect');
els.on("mouseover", function ( d, i ) {
d3.select( this )
.attrs( {
"cursor" : "pointer",
})
.styles({
"stroke": candleSettings.hover,
});
crosshair.style('display', null );
setCrosshair(
xScale( d.date )+xScale.bandwidth()*0.5,
yScale(d.close));
})
.on("mouseout", function (d, i) {
d3.select( this ).attrs({
})
.styles({
"fill" : function( d ) {
return d.close > d.open ? candleSettings.up : candleSettings.down;
},
"stroke" : candleSettings.stroke,
"stroke-width" : "1px",
});
})
eventRect.attrs(
{
'width' : width,
'height' : height
})
.styles({
'opacity' : 0.0,
'display' : null
})
.on('mouseover', function() {
crosshair.style('display', null);
})
.on('mouseout', function() {
crosshair.style('display', 'none');
})
.on('mousemove', function handleMouseMove() {
var mouse = d3.mouse( this );
var x = mouse[0];
var y = mouse[1];
setCrosshair(x,y);
} );
function setCrosshair( x, y ) {
d3.select('#focusLineX')
.attr( 'x1', x )
.attr( 'y1', 0 )
.attr( 'x2', x )
.attr( 'y2', height + 6 );
d3.select('#focusLineY')
.attr( 'x1', -6 )
.attr( 'y1', y )
.attr( 'x2', width )
.attr( 'y2', y );
d3.select("#focusLineXLabel")
.attr( "x", x )
.attr( "y", height+12)
.text( outputFormat(xScale.domain()[Math.floor(x / xScale.step())]) );
d3.select("#focusLineXLabelBackground")
.attr( "transform", "translate( " + (x - crosshairSettings.xlabelWidth * 0.5) + " , " + (height+6) + " )" )
.text( outputFormat(xScale.domain()[Math.floor(x / xScale.step())]) );
d3.select("#focusLineYLabel")
.attr( "transform" , "translate( "+ -9 +", " + y + ")")
.text( formatDecimal( yScale.invert(y) ));
d3.select("#focusLineYLabelBackground")
.attr( "transform" , "translate( "+ (-crosshairSettings.ylabelWidth-6) + ", " + (y-6) + ")")
}
}
(function(data) {
setData(data);
prepareForBuild(data);
buildChart(data);
})(data);
});
}
})(); // We call our anonymous function immediately
</script>
如果您将其复制并粘贴到一个 file.html 中并在本地浏览器上运行它会运行不便,敬请见谅。
我想要实现的是在此烛台图表中使用该 API 示例
我需要在此处进行一些调整才能使用该 URL
var json =[{"close":69.06,"date":"20161020","high":70.1,"low":68.51,"open":68.87,"openInt":0,"volume":736533},{"close":70.58,"date":"20161023","high":70.74,"low":69.67,"open":69.9,"openInt":0,"volume":396860},{"close":71.17,"date":"20161024","high":72.99,"low":71.17,"open":72.6,"openInt":0,"volume":663227}]
在这里实际格式化该数据,因为我所拥有的示例与我所拥有的无关
// DATA STUFF
var formatDecimal = d3.format(',.2f');
var parseDate = d3.timeParse("%Y%m%d"); // 20150630
var outputFormat = d3.timeFormat("%d %b %Y") // 30 June 2015
var dataLoaded = null;
var dataModelJSON = function( d ) {
return {
date : parseDate(+d.date),
open : +d.open,
high : +d.high,
low : +d.low,
close : +d.close,
volume: +d.volume,
openInt : +d.openInt
}
};
var data = json.map( dataModelJSON );
我设法添加了一个示例,说明如何使用纯 JavaScript 从 API 获取数据,现在我在 'var json;' 上有了那个 JSON但我遇到了另一个错误
Uncaught TypeError: Cannot read property 'map' of undefined 我正在尝试从该 JSON 中仅从该属性 ["Time Series (1min)"] 检索数据
【问题讨论】:
标签: javascript jquery json d3.js charts