程序员找房子的正确姿势(附上源码)
点击关注公众号,“技术干货”及时达!
事情起源由于最近部门的办公地点要搬迁了,我租的房子离新场地有足足25公里,而且我对象最近也换了部门,我们以前租的房子在通勤上已经满足不了需求了。好在11月底我们的房子就到期了,所以租房子就被提上日程。(感慨,买房子有鸡毛用啊。)
我对象的办公地点和我新的办公点的距离开车是15公里,地铁是18公里,所以木的办法,只能在中间地带找个房子了。于是乎,我打开的了地图软件,打算把沿途的小区都一个一个记录下来,然后去计算通勤的性价比。
在地图软件上找小区倒是挺简单的,十几分钟我就记了几十个小区,然后我就做了个Excel表格,打算把各个小区到我和我对象办公点的通勤时间、距离都记录下,考虑到多种出勤方式,要统计包括了公交地铁、驾车、骑行。
于是乎,我傻傻的打开地图软件,一个一个导航,记录。当我进行到第十几个小区的时候,我吐了。
于是乎我想到了AI,于是乎我就去问AI,然后AI这么回答了我
可以可以,AI回答的一点毛病没有,有理有据令人信服。
由于我实在不想像SB一样去一个一个查了,于是乎我打开了高德的官网,希望能够得到一点启发。你别说,你还真别说,我还真就发现了一个解决方案。
这不就妥妥的能把问题解决了嘛,于是乎我新建了一个html文件,开始了coding。
我的需求我需要能够输入多个地址、然后选择两个目标地点,用表格展示出距离、时间等信息我需要能够生成Excel文件,方便我记录我需要能够生成图表,能够更直观的看到结果开发思路调用高德API,规划出A地点到B和C的路径,然后整合返回数据,插入表格利用xlsx,生成Excel用eCharts画一个柱状折线图开发中遇到的问题首先就高德Key每天的调用次数限制,不支持我频繁的搜,按理说一天应该5000次啊,但是调了一百多次就会提醒我超了,但是过会又好了由于我是sdk加载的高德依赖,所以三种出行方式的插件会用冲突,所以我只能加载一个插件就改名存以下,再加载另一个由于高德API是异步调用,不支持同步,多并发调用多次会出现有的请求失效,于是乎我想到了用Generator去控制每次请求结束再调用下一次。成果演示源码拷贝就能用哈
你只需要去申请一个高德官网完成开发者认证然后去申请自己的应用,把key和token加上就可以了 传送门
!DOCTYPE htmlhtml head meta charset="utf-8" / meta http-equiv="X-UA-Compatible" content="IE=edge" / meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width" / link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" / script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"/script script type="text/javascript" window._AMapSecurityConfig = { securityJsCode: "你的高德Token", }; /script script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=你的高德Key" /script script type="text/javascript" src="https://cache.amap.com/lbs/static/addToolbar.js" /script script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"/script !-- 引入样式 -- link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" / !-- 引入组件库 -- script src="https://unpkg.com/element-ui/lib/index.js"/script script src="https://unpkg.com/xlsx@0.17.0/dist/xlsx.full.min.js"/script script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"/script /head
body div id="container" style="display: none"/div div id="panel" style="display: none"/div div id="vueContainer" style="padding: 16px" table id="myTable" style="display: none" thead 小区名称/th {{formData.target1}}最短距离/th {{formData.target1}}最快用时/th template v-if="formData.target2" {{formData.target2}}最短距离/th {{formData.target2}}最快用时/th /template /tr /thead tbody tr v-for="item in excelData" {{item.name}}/td {{item.distance1}}/td {{item.time1}}/td template v-if="formData.target2" {{item.distance2}}/td {{item.time2}}/td /template /tr /tbody /table el-form :model="formData" el-form-item label="所在城市" el-input v-model="formData.city" / /el-form-item el-form-item label="起点" el-input type="textarea" :rows="5" v-model="formData.areas" / /el-form-item el-form-item label="终点1" el-input v-model="formData.target1" / /el-form-item el-form-item label="终点2" el-input v-model="formData.target2" / /el-form-item el-form-item label="出行方式" el-select v-model="formData.type" el-option value="Transfer" label="公交地铁"/el-option el-option value="Driving" label="驾车"/el-option el-option value="Riding" label="骑行"/el-option /el-select /el-form-item /el-form el-button type="primary" @click="search" :disabled="loading" 查询 /el-button el-button @click="exportToExcel"生成Excel/el-button el-table border :data="dataList" el-table-column prop="from" label="小区名称"/el-table-column el-table-column :label="formData.target1 || '-'" el-table-column prop="minDistance1" label="最短距离" template #default="{row}" {{row[formData.target1].minDistance}} /template /el-table-column el-table-column prop="minTime1" label="最短时间" template #default="{row}" {{row[formData.target1].minTime}} /template /el-table-column el-table-column prop="name" label="具体路径" template #default="{row}" div v-for="(plan,pIndex) in row[formData.target1].plans" :key="pIndex" 方案{{pIndex +1}}: {{plan.instructions?.join(',')}} b style="color: burlywood" 总用时: {{plan.timeTotal || plan.time || 0}} 总距离:{{plan.distanceTotal || plan.distance || 0}} el-tag type="primary" v-if="plan.shortest" 最短距离 /el-tag el-tag type="danger" v-if="plan.fastest"最快用时/el-tag /div /template /el-table-column /el-table-column el-table-column :label="formData.target2 || '-'" el-table-column prop="minDistance2" label="最短距离" template #default="{row}" {{row[formData.target2].minDistance}} /template /el-table-column el-table-column prop="minTime2" label="最短时间" template #default="{row}" {{row[formData.target2].minTime}} /template /el-table-column el-table-column prop="name" label="具体路径" template #default="{row}" div v-for="(plan,pIndex) in row[formData.target2].plans" :key="pIndex" 方案{{pIndex +1}}: {{plan.instructions?.join(',')}} b style="color: burlywood" 总用时: {{plan.timeTotal || plan.time || 0}} 总距离:{{plan.distanceTotal || plan.distance || 0}} el-tag type="primary" v-if="plan.shortest" 最短距离 /el-tag el-tag type="danger" v-if="plan.fastest"最快用时/el-tag /div /template /el-table-column /el-table-column /el-table div id="chart-container" style="margin-top: 32px; height: 500px; overflow: hidden" /div /div script type="text/javascript" map = new AMap.Map("container", { resizeEnable: true, zoom: 13, }); /script script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=你的高德Key&plugin=AMap.Transfer" /script script type="text/javascript" TransferAMap = AMap; /script script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=你的高德Key&plugin=AMap.Driving" /script script type="text/javascript" DrivingAMap = AMap; /script script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=你的高德Key&plugin=AMap.Riding " /script script type="text/javascript" RidingAMap = AMap; /script script type="text/javascript" const vm = new Vue({ el: "#vueContainer", data() { return { myChart: null, loading: false, dataList: [], formData: { city: "杭州", type: "Transfer", areas: "", target1: "平安金融中心", target2: "金沙中心", }, }; }, computed: { usefulAreas() { return this.formData.areas.split("\n").filter((item) = !!item); }, excelData() { return; }, }, mounted() { const dom = document.getElementById("chart-container"); this.myChart = echarts.init(dom, null, { renderer: "canvas", useDirtyRect: false, }); window.addEventListener("resize", this.myChart.resize); }, methods: { formatDistance(distance) { return (distance / 1000).toFixed(2) + "公里"; }, formatTime(time) { return Math.ceil(time / 60) + "分钟"; }, searchFn(source, from) { return new Promise((resolve, reject) = { switch (this.formData.type) { case "Transfer": //构造公交换乘类 const transfer = new TransferAMap.Transfer({ map, city: this.formData.city, panel: "panel", policy: TransferAMap.TransferPolicy.LEAST_TIME, //乘车策略 }); transfer.search(source, (status, result) = { console.log(result); // result即是对应的公交路线数据信息,相关数据结构文档请参考 https://lbs.amap.com/api/javascript-api/reference/route-search#m_TransferResult if (status === "complete") { const plans = result.plans.map((plan) = { let distanceTotal = 0; let timeTotal = 0; const instructions = plan.segments.map( ({ distance, time, instruction }) = { distanceTotal += distance; timeTotal += time; return instruction; } ); return { distanceTotal, timeTotal, instructions, }; }); plans.forEach((plan, index) = { const others = plans.filter((plan, i) = index !== i); plan.fastest = others.every( (other) = other.timeTotal plan.timeTotal ); plan.shortest = others.every( (other) = other.distanceTotal plan.distanceTotal ); }); const minDistance = plans.reduce((a, b) = a.distanceTotal b.distanceTotal ? a : b ).distanceTotal; const minTime = plans.reduce((a, b) = a.timeTotal b.timeTotal ? a : b ).timeTotal; resolve({ from, minDistance: this.formatDistance(minDistance), minTime: this.formatTime(minTime), plans: plans.map((plan) = ({ ...plan, timeTotal: this.formatTime(plan.timeTotal), distanceTotal: this.formatDistance( plan.distanceTotal ), })), }); } else { log.error("公交路线数据查询失败" + result); reject(); } }); break; case "Driving": const driving = new DrivingAMap.Driving({ map: map, city: this.formData.city, panel: "panel", }); driving.search(source, (status, result) = { console.log(result); if (status === "complete") { const minDistance = result.routes.reduce((a, b) = a.distance b.distance ? a : b ).distance; const minTime = result.routes.reduce((a, b) = a.time b.time ? a : b ).time; resolve({ from, minDistance: this.formatDistance(minDistance), minTime: this.formatTime(minTime), plans: result.routes.map((item) = { return { distance: this.formatDistance(item.distance), time: this.formatTime(item.time), }; }), }); } else { log.error("公交路线数据查询失败" + result); reject(); } }); break; case "Riding": const riding = new RidingAMap.Riding({ map: map, city: this.formData.city, panel: "panel", }); riding.search(source, (status, result) = { if (status === "complete") { const minDistance = result.routes.reduce((a, b) = a.distance b.distance ? a : b ).distance; const minTime = result.routes.reduce((a, b) = a.time b.time ? a : b ).time; resolve({ from, minDistance: this.formatDistance(minDistance), minTime: this.formatTime(minTime), plans: result.routes.map((item) = { return { distance: this.formatDistance(item.distance), time: this.formatTime(item.time), }; }), }); } else { log.error("骑行路线数据查询失败" + result); reject(); } }); break; } }); }, generateRequests: function* (arr) { for (let from of arr) { yield from; } }, async search() { this.loading = true; this.dataList = []; const requests = this.generateRequests(this.usefulAreas); for (let from of requests) { // 使用await关键字等待Generator函数生成的请求完成 let result1 = await this.searchFn( [ { keyword: from, city: this.formData.city }, { keyword: this.formData.target1, city: this.formData.city, }, ], from ); let result2 = await this.searchFn( [ { keyword: from, city: this.formData.city }, { keyword: this.formData.target2, city: this.formData.city, }, ], from ); this.dataList.push({ from, [this.formData.target1]: result1, [this.formData.target2]: result2, }); console.log(this.dataList); } this.loading = false; this.draw(); }, exportToExcel() { var table = document.getElementById("myTable"); var wb = XLSX.utils.table_to_book(table, { sheet: "Sheet JS" }); /*生成Excel文件*/ XLSX.writeFile(wb, "租房.xlsx"); }, draw() { const colors = ["#5470C6", "#91CC75", "#EE6666", "#F9764F"]; const option = { color: colors, tooltip: { trigger: "axis", axisPointer: { type: "cross", }, }, grid: { right: "20%", }, toolbox: { feature: { dataView: { show: true, readOnly: false }, restore: { show: true }, saveAsImage: { show: true }, }, }, legend: { data: [this.formData.target1, this.formData.target2], }, xAxis: [ { type: "category", axisTick: { alignWithLabel: true, }, // prettier-ignore data: this.usefulAreas, }, ], yAxis: [ { type: "value", name: this.formData.target1 + "(距离)", position: "left", alignTicks: true, axisLine: { show: true, lineStyle: { color: colors[0], }, }, axisLabel: { formatter: (value) = `${value / 1000}公里`, }, }, { type: "value", name: this.formData.target2 + "(距离)", position: "left", alignTicks: true, offset: 80, axisLine: { show: true, lineStyle: { color: colors[1], }, }, axisLabel: { formatter: (value) = `${value / 1000}公里`, }, }, { type: "value", name: this.formData.target1 + "(时间)", position: "right", alignTicks: true, axisLine: { show: true, lineStyle: { color: colors[2], }, }, axisLabel: { formatter: (value) = `${value / 60}分钟`, }, }, { type: "value", name: this.formData.target2 + "(时间)", position: "right", alignTicks: true, axisLine: { show: true, lineStyle: { color: colors[3], }, }, axisLabel: { formatter: (value) = `${value / 60}分钟`, }, }, ], series: [ { name: this.formData.target1 + "(距离)", type: "bar", data: this.dataList.map((item) = { return ( parseFloat(item[this.formData.target1].minDistance) * 1000 ); }), }, { name: this.formData.target2 + "(距离)", type: "bar", yAxisIndex: 1, data: this.dataList.map((item) = { return ( parseFloat(item[this.formData.target2].minDistance) * 1000 ); }), }, { name: this.formData.target1 + "(时间)", type: "line", yAxisIndex: 2, data: this.dataList.map((item) = { return parseFloat(item[this.formData.target1].minTime) * 60; }), }, { name: this.formData.target2 + "(时间)", type: "line", yAxisIndex: 2, data: this.dataList.map((item) = { return parseFloat(item[this.formData.target2].minTime) * 60; }), }, ], };
if (option && typeof option === "object") { this.myChart.setOption(option); } }, }, }); /script /body/html
点击关注公众号,“技术干货”及时达!
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线