如何用jQuery协调Rickshaw.js, d3.js



我有一个Laravel网站,它使用jQuery加载通过各种控制器从数据库中提取的数据。我试图添加一个d3可视化的泡沫图表,但我遇到了冲突,我不确定什么是冲突什么。jQuery和d3代码之间似乎存在冲突。但也安装在网站是人力车.js,这是用来生成一些动态时间序列图和人力车是基于d3。我嵌入了一个d3脚本在我的视图文件。因此,它是使用d3的最新版本,我包括一个链接到最新版本之前的d3脚本:

<script src="https://d3js.org/d3.v6.js"></script>

但是,当我console.log d3版本时,它说它是3.5.17,我怀疑这是人力车.js包包含的版本,尽管我找不到告诉我正在使用哪个版本的东西。

在创建用于提取数据并将其传递给d3脚本的jQuery代码之前,我尝试将数据直接从控制器传递到视图文件,并且我得到了d3代码的工作和气泡图的呈现。但是,它们不会动态更新。我把jQuery脚本放在一起,起初很难将数据传递到视图文件中的d3脚本,但最终克服了这个错误,我得到的下一个问题是一个错误,"Uncaught TypeError: svg.append(…).data(…). selectall(…).join(…)。Attr不是一个函数。

我使用的d3代码来自https://d3-graph-gallery.com/网站。错误来自于节点变量的属性设置。回顾原始代码,我发现了这段代码的不同版本,插入它,上面的错误就消失了。相反,我得到了另一个错误,&;Uncaught TypeError: d3。拖拽不是一个函数。在整个代码中,

我还没有找到解决这个错误的方法。我不知道这是否是d3和jQuery之间的冲突,版本冲突或d3.drag()函数的处理根本不正确。有人知道我面临的是什么吗?

下面是提取数据并将其提供给视图文件的jQuery代码:
this.Load = function (data) {
if (_xhr) {
_xhr.abort();
_xhr = null;
}
_this.SetLoading(true);
_xhr = $.ajax({
url: $("meta[name='root']").attr("content") + '/app/heatmap/bubble',
type: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: {
date_id: data.dateRange.date,
venue_id: data.venue,
floor_id: data.floor,
zone_id: data.zone
},
dataType: 'JSON',
async: true,
cache: false,
error: function (jqXHR, textStatus, errorThrown) {
_this.SetLoading(false);
},
success: function (response) {
_this.SetLoading(false);
_this.SetKey(data.dateRange.key);
_this.Update(response);
}
});
};
this.Update = function (data) {
if (_.isUndefined(data) || _.isNull(data)) {
data = {};
}
if (this.BubbleChart && data) {
this.BubbleChart.Update(displayChart(data));
}
};

这里是视图文件的一部分,保存d3脚本和渲染图表的相关HTML。

<div id="heatmap-bubble" class="block block-condensed no-margin {{ getDateRangeKey(getMainControlsSelections()->dateRange) }}"
data-venue="{{ $mainControlsData->venue ? $mainControlsData->venue->id : '' }}"
>
<div class="app-heading">
<div class="title">
<h2>{{ trans('app/heatmap.map.title') }}</h2>
<p>{{ trans('app/heatmap.map.subtitle') }}</p>
</div>
<div class="heading-elements">
<div class="{{ $mainControlsData->venue && $mainControlsData->venue->spotData && count($mainControlsData->venue->spotData->floors) > 1 && !$mainControlsData->floor ? '' : 'hidden' }}">
<label>
<span class="fa fa-object-ungroup"></span>
</label>
<select id="mapControls-floor"
data-noneSelectedText="{{ trans('app/main.mainControls.floor.noneSelectedText') }}"
{{ count($mainControlsData->venue->spotData->floors) > 1 ? '' : 'disabled' }}
>
@if($mainControlsData->venue && isset($mainControlsData->venue->spotData->floors))
@foreach($mainControlsData->venue->spotData->floors as $floor)
<option value="{{ $floor->id }}"{{ ($mainControlsData->floor && $mainControlsData->floor->id === $floor->id) ? ' selected' : '' }}>{{ $floor->name }}</option>
@endforeach
@endif
</select>
</div>
</div>
</div>
<div class="block-content">
<div class="row">
<div id="bubble-chart">
<span id="bubbleData"
data-type="text"
data-visitors
></span>

<script src="https://d3js.org/d3.v6.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<div id="bubble_viz"></div>
<script>
var displayChart = function(data) {
// set the dimensions and margins of the graph
const width = 700
const height = 460
// append the svg object to the body of the page
const svg = d3.select("#bubble_viz")
.append("svg")
.attr("width", width)
.attr("height", height)
var zones = [];
for (var i = 0, l = data.length; i < l; i++) {
var obj = data[i];
zones[i] = obj.zone;
}
// Color palette for continents?
const color = d3.scale.ordinal()
.domain([1, 2, 3, 4, 5, 6,7])
.range(["#98ccd9", "#79b9c9", "#549eb0", "#6f939b", "#217185", "#cfe3e8", "#044e61"]);
// Size scale for venues
const size = d3.scale.linear()
.domain([0, 100])
.range([15,100])  // circle will be between 15 and 100 px wide
// create a tooltip
const Tooltip = d3.select("#bubble_viz")
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "#ebeef2")
.style("border", "solid")
.style("border-width", "2px")
.style("border-radius", "5px")
.style("padding", "5px")
// Three function that change the tooltip when user hover / move / leave a cell
const mouseover = function(event, d) {
Tooltip
.style("opacity", 1)
}
const mousemove = function(event, d) {
Tooltip
.html('<b>' + d.zone + '</b>' + "<br>" + d.value + " visitors")
.style("left", (event.x/2-300) + "px")
.style("top", (event.y/2-200) + "px")
}
var mouseleave = function(event, d) {
Tooltip
.style("opacity", 0)
}
// Initialize the circle: all located at the center of the svg area
var node = svg.append("g")
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class", "node")
.attr("r", d => size(d.value))
.attr("cx", width)
.attr("cy", height)
.style("fill", d => color(d.zone))
.style("fill-opacity", 0.8)
.attr("stroke", "black")
.style("stroke-width", 1)
.on("mouseover", mouseover) // What to do when hovered
.on("mousemove", mousemove)
.on("mouseleave", mouseleave)
.call(d3.drag() // call specific function when circle is dragged
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
let texts = svg.selectAll(null)
.data(data)
.enter()
.append('text')
.attr("text-anchor", "middle")
.text(d => d.zone)
.attr('color', 'black')
.attr('font-size', 15)
// Features of the forces applied to the nodes:
const simulation = d3.forceSimulation()
.force("center", d3.forceCenter().x(width / 2).y(height / 2)) // Attraction to the center of the svg area
.force("charge", d3.forceManyBody().strength(.1)) // Nodes are attracted one each other of value is > 0
.force("collide", d3.forceCollide().strength(.2).radius(function(d){ return (size(d.value)+3) }).iterations(1)) // Force that avoids circle overlapping
// Apply these forces to the nodes and update their positions.
// Once the force algorithm is happy with positions ('alpha' value is low enough), simulations will stop.
simulation
.nodes(data)
.on("tick", function(d){
node
.attr("cx", d => d.x)
.attr("cy", d => d.y)
texts
.attr("cx", d => d.x)
.attr("cy", d => d.y)
});
// What happens when a circle is dragged?
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(.03).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(.03);
d.fx = null;
d.fy = null;
}
}
</script>
</div><!-- /#mapContainer -->
<div id="mapSlider">
<!--<div class="left"></div>-->
<div class="right">
<div class="slider-container"></div><!-- /.slider-container -->
</div>
</div>
</div><!-- /.row -->
</div><!-- /.block-content -->
</div><!-- /#heatmap-bubble -->

有人知道吗?

我发现问题是版本冲突。我正在寻找的功能在d3 v3.5.17中不可用。我已经在当前版本的代码调整上取得了进展。我需要在不破坏d3代码的其他功能使用的情况下获得d3的升级版本。我对此做了很多研究,发现rickshaw.js的仓库在几年前就被废弃了。我发现了一个包含d3 v4升级的分支,并且正在整理如何最好地将公共/资产/应用程序/供应商版本的rickshaw与v4升级到d3,并避免对站点中的遗留图表进行破坏性更改。然后我偶然发现了我认为在这种情况下的完美解决方案,即在一页中包含两个不同版本的d3。这个解决方案在这里找到:https://chewett.co.uk/blog/2021/how-to-load-multiple-d3-versions-at-once/在实现之后,我的旧图表工作正常,我的新气泡也工作正常。

我发现问题是版本冲突。我正在寻找的功能在d3 v3.5.17中不可用。我已经在当前版本的代码调整上取得了进展。但是现在我需要在不破坏代码的其他功能使用的情况下升级d3的版本。

最新更新