Html canvas 元素在 drag/drop 之后将宽度和高度重置为零
Html canvas element resets width and height to zero after drag/drop
我正在开发可自定义的仪表板,用户可以在其中(除其他功能外)拖动仪表板图块(div
元素)并将这些图块重新放置在仪表板中的任何位置。
HTML结构
html 结构类似于下面的代码片段
<div class="dashboard">
<div class="tile"><canvas/></div>
<div class="tile"><canvas/></div>
<div class="tile empty"></div>
</div>
预期行为
想法是 .dashboard
可以包含多个 .tiles
,每个 .tile
包含一个报告(在 canvas
元素上绘制的 graph/chart) .其中一些 .tiles
可以是 .empty
,如不包含任何报告。然后可以将 .tile
拖放到 .empty
方块中。
因此,div.tile.empty
用作“拖放区”,而 div.tile
将是可拖动元素。下面添加了一个 fiddler 片段,作为一个简单但功能齐全的示例。
使用的库
- jQuery
- ChartJs。在 canvas
上绘制图表的开源 js 库
问题
一切似乎都运行良好,只是在删除 .tile
之后 canvas 将其 width/height 重置为零!!!而且我还没有找到一种方法可以将其重置为 drag/drop 事件之前的原始尺寸。即使我手动设置 width/height,canvas.
上也不会绘制任何内容
问题
有什么方法可以保留(或恢复)canvas 的 width/height,同时在 drag/dropping 后重新绘制图形?
我尝试使用 chartjs
的 update
、render
和 resize
函数无济于事。
这些函数的文档可以在下面的 link(版本 3.5.0)...
中找到
https://www.chartjs.org/docs/3.5.0/developers/api.html
代码示例
这是一个示例代码片段,您可以在其中重现上述问题。这些按钮是我在 drag/dropping.
之后尝试 update/resize/re-render 图表
var $sourceTile = null;
var charts = [];
$(() => {
$(".buttons-container a").on("click", btnClickHandler);
renderChart("canvas1", 'doughnut');
renderChart("canvas2", "line");
attachDropHandlers();
});
attachDropHandlers = () => {
$(".tile").off("dragstart").off("dragover").off("drop");
$(".tile .report").on("dragstart", dragStartHandler);
$(".tile.empty").on("dragover", dragOverHandler);
$(".tile.empty").on("drop", dropHandler);
}
dragStartHandler = (e) => {
const $target = $(e.target);
const $report = $target.is(".report") ? $target : $target.parents(".report");
$sourceTile = $report.parents(".tile");
e.originalEvent.dataTransfer.setData("application/dashboard", $report[0].id);
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.dropEffect = "move";
}
dragOverHandler = (e) => {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = "move";
}
dropHandler = (e) => {
e.preventDefault();
const id = e.originalEvent.dataTransfer.getData("application/dashboard");
if (id) {
$("#" + id).appendTo(".tile.empty");
$(".tile.empty").removeClass("empty");
if ($sourceTile) {
$sourceTile.addClass("empty");
attachDropHandlers();
}
}
}
renderChart = (canvasId, type) => {
const labels = ["Red", "Green", "Blue"];
const data = [30, 25, 42];
const colors = ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'];
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
type: type,
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: colors,
borderColor: colors,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 1,
plugins: {
legend: {
display: false
},
htmlLegend: {
tile: this.$tile,
maxItems: 8
}
}
}
});
chart.update();
charts.push(chart);
}
btnClickHandler = (e) => {
const button = e.target.id;
switch (button) {
case "btn1":
charts.forEach((chart) => chart.update());
break;
case "btn2":
charts.forEach((chart) => chart.update('resize'));
break;
case "btn3":
charts.forEach((chart) => chart.render());
break;
case "btn4":
charts.forEach((chart) => chart.resize());
break;
case "btn5":
charts.forEach((chart) => chart.resize(120, 120));
break;
}
}
html,
body {
background-color: #eee;
}
h3 {
margin: 0;
padding: 10px;
}
.dashboard {}
.dashboard .tile {
display: inline-block;
vertical-align: top;
margin: 5px;
height: 250px;
width: 250px;
}
.tile.empty {
border: 2px dashed #ccc;
}
.report {
height: 250px;
width: 250px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.buttons-container a {
background-color: #673AB7;
color: #EDE7F6;
cursor: pointer;
padding: 10px 15px;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container a:hover {
background-color: #7E57C2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.6.0/dist/chart.min.js"></script>
<div class="dashboard">
<div class="tile">
<div id="report1" class="report" draggable="true">
<h3>
Report 1
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas1"></canvas>
</div>
</div>
</div>
<div class="tile">
<div id="report2" class="report" draggable="true">
<h3>
Report 2
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas2"></canvas>
</div>
</div>
</div>
<div class="tile empty">
</div>
</div>
<div class="buttons-container">
<a id="btn1">update()</a>
<a id="btn2">update('resize')</a>
<a id="btn3">render()</a>
<a id="btn4">resize()</a>
<a id="btn5">resize(120,120)</a>
</div>
这是一个Chart.js issue of version 3.6.0 and fixed in version 3.6.1。示例如下:
var $sourceTile = null;
var charts = [];
$(() => {
$(".buttons-container a").on("click", btnClickHandler);
renderChart("canvas1", 'doughnut');
renderChart("canvas2", "line");
attachDropHandlers();
});
attachDropHandlers = () => {
$(".tile").off("dragstart").off("dragover").off("drop");
$(".tile .report").on("dragstart", dragStartHandler);
$(".tile.empty").on("dragover", dragOverHandler);
$(".tile.empty").on("drop", dropHandler);
}
dragStartHandler = (e) => {
const $target = $(e.target);
const $report = $target.is(".report") ? $target : $target.parents(".report");
$sourceTile = $report.parents(".tile");
e.originalEvent.dataTransfer.setData("application/dashboard", $report[0].id);
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.dropEffect = "move";
}
dragOverHandler = (e) => {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = "move";
}
dropHandler = (e) => {
e.preventDefault();
const id = e.originalEvent.dataTransfer.getData("application/dashboard");
if (id) {
$("#" + id).appendTo(".tile.empty");
$(".tile.empty").removeClass("empty");
if ($sourceTile) {
$sourceTile.addClass("empty");
attachDropHandlers();
}
}
}
renderChart = (canvasId, type) => {
const labels = ["Red", "Green", "Blue"];
const data = [30, 25, 42];
const colors = ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'];
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
type: type,
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: colors,
borderColor: colors,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 1,
plugins: {
legend: {
display: false
},
htmlLegend: {
tile: this.$tile,
maxItems: 8
}
}
}
});
chart.update();
charts.push(chart);
}
btnClickHandler = (e) => {
const button = e.target.id;
switch (button) {
case "btn1":
charts.forEach((chart) => chart.update());
break;
case "btn2":
charts.forEach((chart) => chart.update('resize'));
break;
case "btn3":
charts.forEach((chart) => chart.render());
break;
case "btn4":
charts.forEach((chart) => chart.resize());
break;
case "btn5":
charts.forEach((chart) => chart.resize(120, 120));
break;
}
}
html,
body {
background-color: #eee;
}
h3 {
margin: 0;
padding: 10px;
}
.dashboard {}
.dashboard .tile {
display: inline-block;
vertical-align: top;
margin: 5px;
height: 250px;
width: 250px;
}
.tile.empty {
border: 2px dashed #ccc;
}
.report {
height: 250px;
width: 250px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.buttons-container a {
background-color: #673AB7;
color: #EDE7F6;
cursor: pointer;
padding: 10px 15px;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container a:hover {
background-color: #7E57C2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.6.1/dist/chart.min.js"></script>
<div class="dashboard">
<div class="tile">
<div id="report1" class="report" draggable="true">
<h3>
Report 1
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas1"></canvas>
</div>
</div>
</div>
<div class="tile">
<div id="report2" class="report" draggable="true">
<h3>
Report 2
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas2"></canvas>
</div>
</div>
</div>
<div class="tile empty">
</div>
</div>
<div class="buttons-container">
<a id="btn1">update()</a>
<a id="btn2">update('resize')</a>
<a id="btn3">render()</a>
<a id="btn4">resize()</a>
<a id="btn5">resize(120,120)</a>
</div>
我正在开发可自定义的仪表板,用户可以在其中(除其他功能外)拖动仪表板图块(div
元素)并将这些图块重新放置在仪表板中的任何位置。
HTML结构
html 结构类似于下面的代码片段
<div class="dashboard">
<div class="tile"><canvas/></div>
<div class="tile"><canvas/></div>
<div class="tile empty"></div>
</div>
预期行为
想法是 .dashboard
可以包含多个 .tiles
,每个 .tile
包含一个报告(在 canvas
元素上绘制的 graph/chart) .其中一些 .tiles
可以是 .empty
,如不包含任何报告。然后可以将 .tile
拖放到 .empty
方块中。
因此,div.tile.empty
用作“拖放区”,而 div.tile
将是可拖动元素。下面添加了一个 fiddler 片段,作为一个简单但功能齐全的示例。
使用的库
- jQuery
- ChartJs。在 canvas 上绘制图表的开源 js 库
问题
一切似乎都运行良好,只是在删除 .tile
之后 canvas 将其 width/height 重置为零!!!而且我还没有找到一种方法可以将其重置为 drag/drop 事件之前的原始尺寸。即使我手动设置 width/height,canvas.
问题
有什么方法可以保留(或恢复)canvas 的 width/height,同时在 drag/dropping 后重新绘制图形?
我尝试使用 chartjs
的 update
、render
和 resize
函数无济于事。
这些函数的文档可以在下面的 link(版本 3.5.0)...
https://www.chartjs.org/docs/3.5.0/developers/api.html
代码示例
这是一个示例代码片段,您可以在其中重现上述问题。这些按钮是我在 drag/dropping.
之后尝试 update/resize/re-render 图表var $sourceTile = null;
var charts = [];
$(() => {
$(".buttons-container a").on("click", btnClickHandler);
renderChart("canvas1", 'doughnut');
renderChart("canvas2", "line");
attachDropHandlers();
});
attachDropHandlers = () => {
$(".tile").off("dragstart").off("dragover").off("drop");
$(".tile .report").on("dragstart", dragStartHandler);
$(".tile.empty").on("dragover", dragOverHandler);
$(".tile.empty").on("drop", dropHandler);
}
dragStartHandler = (e) => {
const $target = $(e.target);
const $report = $target.is(".report") ? $target : $target.parents(".report");
$sourceTile = $report.parents(".tile");
e.originalEvent.dataTransfer.setData("application/dashboard", $report[0].id);
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.dropEffect = "move";
}
dragOverHandler = (e) => {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = "move";
}
dropHandler = (e) => {
e.preventDefault();
const id = e.originalEvent.dataTransfer.getData("application/dashboard");
if (id) {
$("#" + id).appendTo(".tile.empty");
$(".tile.empty").removeClass("empty");
if ($sourceTile) {
$sourceTile.addClass("empty");
attachDropHandlers();
}
}
}
renderChart = (canvasId, type) => {
const labels = ["Red", "Green", "Blue"];
const data = [30, 25, 42];
const colors = ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'];
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
type: type,
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: colors,
borderColor: colors,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 1,
plugins: {
legend: {
display: false
},
htmlLegend: {
tile: this.$tile,
maxItems: 8
}
}
}
});
chart.update();
charts.push(chart);
}
btnClickHandler = (e) => {
const button = e.target.id;
switch (button) {
case "btn1":
charts.forEach((chart) => chart.update());
break;
case "btn2":
charts.forEach((chart) => chart.update('resize'));
break;
case "btn3":
charts.forEach((chart) => chart.render());
break;
case "btn4":
charts.forEach((chart) => chart.resize());
break;
case "btn5":
charts.forEach((chart) => chart.resize(120, 120));
break;
}
}
html,
body {
background-color: #eee;
}
h3 {
margin: 0;
padding: 10px;
}
.dashboard {}
.dashboard .tile {
display: inline-block;
vertical-align: top;
margin: 5px;
height: 250px;
width: 250px;
}
.tile.empty {
border: 2px dashed #ccc;
}
.report {
height: 250px;
width: 250px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.buttons-container a {
background-color: #673AB7;
color: #EDE7F6;
cursor: pointer;
padding: 10px 15px;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container a:hover {
background-color: #7E57C2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.6.0/dist/chart.min.js"></script>
<div class="dashboard">
<div class="tile">
<div id="report1" class="report" draggable="true">
<h3>
Report 1
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas1"></canvas>
</div>
</div>
</div>
<div class="tile">
<div id="report2" class="report" draggable="true">
<h3>
Report 2
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas2"></canvas>
</div>
</div>
</div>
<div class="tile empty">
</div>
</div>
<div class="buttons-container">
<a id="btn1">update()</a>
<a id="btn2">update('resize')</a>
<a id="btn3">render()</a>
<a id="btn4">resize()</a>
<a id="btn5">resize(120,120)</a>
</div>
这是一个Chart.js issue of version 3.6.0 and fixed in version 3.6.1。示例如下:
var $sourceTile = null;
var charts = [];
$(() => {
$(".buttons-container a").on("click", btnClickHandler);
renderChart("canvas1", 'doughnut');
renderChart("canvas2", "line");
attachDropHandlers();
});
attachDropHandlers = () => {
$(".tile").off("dragstart").off("dragover").off("drop");
$(".tile .report").on("dragstart", dragStartHandler);
$(".tile.empty").on("dragover", dragOverHandler);
$(".tile.empty").on("drop", dropHandler);
}
dragStartHandler = (e) => {
const $target = $(e.target);
const $report = $target.is(".report") ? $target : $target.parents(".report");
$sourceTile = $report.parents(".tile");
e.originalEvent.dataTransfer.setData("application/dashboard", $report[0].id);
e.originalEvent.dataTransfer.effectAllowed = "move";
e.originalEvent.dataTransfer.dropEffect = "move";
}
dragOverHandler = (e) => {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = "move";
}
dropHandler = (e) => {
e.preventDefault();
const id = e.originalEvent.dataTransfer.getData("application/dashboard");
if (id) {
$("#" + id).appendTo(".tile.empty");
$(".tile.empty").removeClass("empty");
if ($sourceTile) {
$sourceTile.addClass("empty");
attachDropHandlers();
}
}
}
renderChart = (canvasId, type) => {
const labels = ["Red", "Green", "Blue"];
const data = [30, 25, 42];
const colors = ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'];
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
type: type,
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: colors,
borderColor: colors,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 1,
plugins: {
legend: {
display: false
},
htmlLegend: {
tile: this.$tile,
maxItems: 8
}
}
}
});
chart.update();
charts.push(chart);
}
btnClickHandler = (e) => {
const button = e.target.id;
switch (button) {
case "btn1":
charts.forEach((chart) => chart.update());
break;
case "btn2":
charts.forEach((chart) => chart.update('resize'));
break;
case "btn3":
charts.forEach((chart) => chart.render());
break;
case "btn4":
charts.forEach((chart) => chart.resize());
break;
case "btn5":
charts.forEach((chart) => chart.resize(120, 120));
break;
}
}
html,
body {
background-color: #eee;
}
h3 {
margin: 0;
padding: 10px;
}
.dashboard {}
.dashboard .tile {
display: inline-block;
vertical-align: top;
margin: 5px;
height: 250px;
width: 250px;
}
.tile.empty {
border: 2px dashed #ccc;
}
.report {
height: 250px;
width: 250px;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.buttons-container a {
background-color: #673AB7;
color: #EDE7F6;
cursor: pointer;
padding: 10px 15px;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
}
.buttons-container a:hover {
background-color: #7E57C2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.6.1/dist/chart.min.js"></script>
<div class="dashboard">
<div class="tile">
<div id="report1" class="report" draggable="true">
<h3>
Report 1
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas1"></canvas>
</div>
</div>
</div>
<div class="tile">
<div id="report2" class="report" draggable="true">
<h3>
Report 2
</h3>
<div style="padding:10px;height:180px;width:180px">
<canvas id="canvas2"></canvas>
</div>
</div>
</div>
<div class="tile empty">
</div>
</div>
<div class="buttons-container">
<a id="btn1">update()</a>
<a id="btn2">update('resize')</a>
<a id="btn3">render()</a>
<a id="btn4">resize()</a>
<a id="btn5">resize(120,120)</a>
</div>