简体   繁体   English

Javascript 按钮 onclick 事件调用 function 内部 ZC1C425268E68385D14AB5074C17A 模块

[英]Javascript button onclick event to call function inside function in module

I'm drawing and coloring lines based on data with D3.js and want to update their colors when clicking a button.我正在根据 D3.js 的数据绘制和着色线条,并希望在单击按钮时更新其 colors。 My question is: how can I call colorP1() and colorP2() , declared in function drawLines in drawLines.js , from the onclick event of one of the buttons in index.html ?我的问题是:如何从 index.ZFC35FDC70D5FC67A53EZ 中的一个按钮的onclick事件调用在drawLines.js中的index.html drawLines中声明的colorP1()colorP2()

I have tried:我努力了:

  1. using the window.drawLines = drawLines trick and have the onclick event refer to window.drawLines.colorP2() , but I get Uncaught TypeError: colorP2 is not a function using the window.drawLines = drawLines trick and have the onclick event refer to window.drawLines.colorP2() , but I get Uncaught TypeError: colorP2 is not a function
  2. using window.colorP2 = colorP2 , but I don't know how the import would work in this case使用window.colorP2 = colorP2 ,但我不知道在这种情况下导入将如何工作

Any ideas to enlighten the mind of this humble beginner?有什么想法可以启发这个卑微的初学者的思想吗? As I understand it, colorP1() and colorP2() have to stay inside drawLines() because they need the data and lines variables from drawLines() --feel free to prove me wrong here.据我了解, colorP1()colorP2()必须保留在drawLines()中,因为它们需要drawLines() () 中的datalines变量——在这里随时证明我错了。

index.html索引.html

<html>
<head>
<style>
.line {
    stroke-width: 4px;
    fill: none;
}
</style>
</head>

<script src="https://d3js.org/d3.v6.min.js"></script>
<script type="module">
  import {drawLines} from './drawLines.js';

  d3.json("test.geojson").then(drawLines);
</script>

<body>
    <svg id='map'></svg>
    <button onclick="colorP1()">colorP1</button>
    <button onclick="colorP2()">colorP2</button>

</body>
</html>

drawLines.js drawLines.js

function colorInterpolate(data, property) {
    let max_d = d3.max(data.features.map(d => d.properties[property]));
    let range = [max_d, 1];
    return d3.scaleSequential().domain(range).interpolator(d3.interpolateViridis); 
}

export function drawLines(data) {

    let width = 900,
        height = 500,
        initialScale = 1 << 23,
        initialCenter = [-74.200698022608137, 40.034504451003734]

    let svg = d3.select('#map')
        .attr('height', height)
        .attr('width', width)

    let projection = d3.geoMercator()
        .scale(initialScale)
        .center(initialCenter)
        .translate([width / 2, height / 2])

    let path = d3.geoPath(projection)

    let myColor = colorInterpolate(data, 'p1');

    let lines = svg.append('g')

    lines.selectAll('path')
        .data(data.features)
        .join('path')
        .attr('class', 'line')
        .attr('d', path)
        .attr("stroke", function(d) {
                return myColor(d.properties.p1);
            })

    function colorP2() {
        let myColor = colorInterpolate(data, 'p2');
        lines.selectAll('path')
            .attr("stroke", d => myColor(d.properties.p2))
    }

    function colorP1() {
        let myColor = colorInterpolate(data, 'p1');
        lines.selectAll('path')
            .attr("stroke", d => myColor(d.properties.p1))
    }
}

test.geojson test.geojson

{
"type": "FeatureCollection",
"name": "lines",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": 3, "p1": 1, "p2": 3}, "geometry": { "type": "LineString", "coordinates": [ [ -74.201304101157845, 40.033790926216739 ], [ -74.201226425025339, 40.033761910802717 ], [ -74.201164135201353, 40.033738641825124 ] ] } },
{ "type": "Feature", "properties": { "id": 4, "p1": 2, "p2": 2}, "geometry": { "type": "LineString", "coordinates": [ [ -74.200521185229846, 40.034804885753857 ], [ -74.200535458528648, 40.034780636493231 ], [ -74.200698022608137, 40.034504451003734 ], [ -74.200932444446437, 40.034106179618831 ], [ -74.201017665586349, 40.033961391736824 ] ] } }
]
}

You can call like this to call inner functions:您可以像这样调用内部函数:

<button onclick="(new drawLines().colorP1())">colorP1</button>
<button onclick="(new drawLines().colorP2())">colorP2</button>

Your assumption is wrong:你的假设是错误的:

As I understand it, colorP1() and colorP2() have to stay inside drawLines() because they need the data and lines variables from drawLines()据我了解, colorP1() 和 colorP2() 必须留在 drawLines() 内,因为它们需要 drawLines() 中的数据和线条变量

D3 binds data to the elements entered with .data(data).join() or .data(data).enter() . D3 将数据绑定到使用.data(data).join().data(data).enter()输入的元素。 The datum is attached to the node.基准附加到节点。 When using .attr("something",function(d) { the d refers to the bound datum, not the original data array. So, you don't need the original data array, it is part of the DOM element.使用.attr("something",function(d) {时, d指的是绑定数据,而不是原始数据数组。因此,您不需要原始数据数组,它是 DOM 元素的一部分。

Also, you don't need lines because you can remake that selection: d3.selectAll("paths") or d3.selectAll(".line") .此外,您不需要lines ,因为您可以重新选择: d3.selectAll("paths")d3.selectAll(".line")

So, you can move the p1/p2 functions outside of your drawLines function.因此,您可以将 p1/p2 函数移到 drawLines function 之外。

As I wanted to simplify for the snippet below, I've got a function that is passed data to draw some circles.正如我想简化下面的代码片段一样,我有一个 function 传递数据以绘制一些圆圈。 I then assign event listeners to the buttons (I could also use onclick="" attributes on the buttons directly) with D3 to call functions that recolor the circles:然后我使用 D3 将事件侦听器分配给按钮(我也可以直接在按钮上使用onclick=""属性)来调用重新着色圆圈的函数:

function color1() {
 d3.selectAll("circle")
   .attr("fill",d=>d.color1);
}

The function access the bound datum and a given property ( d=>d.color1 ) and by using d3.selectAll() we can select all the circles that exist at the time of the click: function 访问绑定数据和给定属性( d=>d.color1 ),通过使用d3.selectAll()我们可以 select 单击时存在的所有圆圈:

 function draw(data) { var svg = d3.select("body").append("svg").attr("width", 300).attr("height", 200); svg.selectAll("circle").data(data).enter().append("circle").attr("cx",d=>dx).attr("cy",d=>dy).attr("fill",d=>d.color2).attr("r", 20); } draw([{x: 100,y:50, color1: "steelblue",color2:"crimson"},{x:200,y:50,color1:"steelblue",color2:"crimson"}]) d3.selectAll("button").data([0,1]).on("click", function(event,d) { if (d) color2(); else color1(); }) function color1() { d3.selectAll("circle").attr("fill",d=>d.color1); } function color2() { d3.selectAll("circle").attr("fill",d=>d.color2); }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script> <div> <button> Blue </button> <button> Red </button> </div>

If you need the data array itself, you can extract that with d3.selectAll("elements").data()如果您需要数据数组本身,您可以使用d3.selectAll("elements").data()提取它

Of course, we could also append the buttons in your drawLines function, which would potentially make a cleaner outcome, especially if the buttons are dependent on the data in any form.当然,我们也可以 append 您的 drawLines function 中的按钮,这可能会产生更清晰的结果,特别是如果按钮依赖于任何形式的数据。 This way if you ever wanted to change the buttons or the functions, everything is in one place, for example:这样,如果您想更改按钮或功能,一切都在一个地方,例如:

 var geojson = { "type": "FeatureCollection","name": "lines","crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },"features": [{ "type": "Feature", "properties": { "id": 3, "p1": 1, "p2": 3}, "geometry": { "type": "LineString", "coordinates": [ [ -74.201304101157845, 40.033790926216739 ], [ -74.201226425025339, 40.033761910802717 ], [ -74.201164135201353, 40.033738641825124 ] ] } },{ "type": "Feature", "properties": { "id": 4, "p1": 2, "p2": 2}, "geometry": { "type": "LineString", "coordinates": [ [ -74.200521185229846, 40.034804885753857 ], [ -74.200535458528648, 40.034780636493231 ], [ -74.200698022608137, 40.034504451003734 ], [ -74.200932444446437, 40.034106179618831 ], [ -74.201017665586349, 40.033961391736824 ] ] } }]}; function drawLines(data) { let width = 500, height = 400, initialScale = 1 << 23, initialCenter = [-74.200698022608137, 40.034504451003734] let svg = d3.select('#map').attr('height', height).attr('width', width) let projection = d3.geoMercator().fitSize([width,height],data) let path = d3.geoPath(projection) let myColor = colorInterpolate(data, 'p1'); let lines = svg.append('g') lines.selectAll('path').data(data.features).join('path').attr('class', 'line').attr('d', path) colorBy("p1"); function colorBy(property) { let myColor = colorInterpolate(property); lines.selectAll('path').attr("stroke", d => myColor(d.properties[property])) } function colorInterpolate(property) { let max_d = d3.max(data.features.map(d => d.properties[property])); let range = [max_d, 1]; return d3.scaleSequential().domain(range).interpolator(d3.interpolateViridis); } d3.selectAll(".property").data(["p1","p2"]).enter().append("button").attr("class","property").text(d=>d).on("click", function(_,d) { colorBy(d); }).lower(); } drawLines(geojson);
 .line { stroke-width: 4px; fill: none; }
 <script src="https://d3js.org/d3.v6.min.js"></script> <svg id='map'></svg>

and work example for continue working...和继续工作的工作示例......

 var json1 ='{ "type": "FeatureCollection", "name":"lines", "crs": { "type": "name", "properties":{ "name":"urn:ogc:def:crs:OGC:1.3:CRS84" }}, "features": [{ "type": "Feature", "properties": { "id": 3, "p1": 1, "p2": 3}, "geometry": {"type": "LineString","coordinates":[[ -74.201304101157845, 40.033790926216739],[-74.201226425025339,40.033761910802717 ],[-74.201164135201353,40.033738641825124]]}},{"type": "Feature","properties":{ "id": 4, "p1": 2, "p2":2 },"geometry": { "type": "LineString", "coordinates": [[ -74.200521185229846, 40.034804885753857 ],[ -74.200535458528648, 40.034780636493231 ],[ -74.200698022608137, 40.034504451003734 ],[ -74.200932444446437, 40.034106179618831 ],[ -74.201017665586349, 40.033961391736824 ]]}}]}'; var width = 900, height = 500, initialScale = 1 << 23, initialCenter = [-74.198698022608137, 40.034504451003734] var svg = d3.select('#map').attr('height', height).attr('width', width); var lines = svg.append('g'); var projection = d3.geoMercator().scale(initialScale).center(initialCenter).translate([width / 2, height / 2]) var path = d3.geoPath(projection) function colorInterpolate(data, property) { let max_d = d3.max(data.features.map(d => d.properties[property])); let range = [max_d, 1]; return d3.scaleSequential().domain(range).interpolator(d3.interpolateViridis); } function drawLines(data) { let myColor = colorInterpolate(data, 'p1'); lines.selectAll('path').data(data.features).join('path').attr('class', 'line').attr('d', path).attr("stroke", function(d) { return myColor(d.properties.p1); }); } function colorP2(data){ let myColor = colorInterpolate(data, 'p2'); lines.selectAll('path').attr("stroke", d=>myColor(d.properties.p2)); } function colorP1(data){ let myColor = colorInterpolate(data, 'p1'); lines.selectAll('path').attr("stroke", d=>myColor(d.properties.p1)); }
 <html> <head> <style>.line { stroke-width: 4px; fill: none; } </style> </head> <script src="https://d3js.org/d3.v6.min.js"></script> <script type="module"> //import {drawLines} from './drawLines.js'; //d3.json("test.geojson").then(drawLines); drawLines(JSON.parse(json1)); </script> <body> <svg id='map'></svg> <button onclick="colorP1(JSON.parse(json1))">colorP1</button> <button onclick="colorP2(JSON.parse(json1))">colorP2</button> </body> </html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM