- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在开发一个网络应用程序,它包括一个我绘制函数图形的部分,坐标系是由 Canvas 制作的。问题是,我无法放大坐标系。我想让它能够放大和缩小+使用鼠标移动坐标系。放大/缩小时,x 和 y 值也应该增加/减少。
有人可以帮我解决这个问题吗?
我搜索了一些解决方案,但找不到任何有用的东西。这就是为什么我决定在这里问这个问题。
这是我的代码:
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
<!--Canva startup-->
<script>
// Setup values
var height = 300;
var width = 300;
var zoomFactor = 15;
// --------
var c = document.getElementById("myCanvas");
var xZero = width / 2;
var yZero = height / 2;
var ctx = c.getContext("2d");
// Draw Cord-System-Grid
ctx.beginPath();
ctx.moveTo(xZero, 0);
ctx.lineTo(xZero, height);
ctx.strokeStyle = "#000000";
ctx.stroke();
ctx.moveTo(0, yZero);
ctx.lineTo(width, yZero);
ctx.strokeStyle = "#000000";
ctx.stroke();
ctx.beginPath();
// Draw Numbers
ctx.font = "10px Georgia";
var heightTextX = yZero + 10;
for(var i = 0; i < width; i = i + width / 10) {
var numberX = (-1 * xZero / zoomFactor) + i / zoomFactor;
ctx.fillText(numberX, i, heightTextX);
}
var heightTextY = yZero + 10;
for(var n = 0; n < height; n = n + height / 10) {
var numberY = (-1 * yZero / zoomFactor) + n / zoomFactor;
if(numberY !== 0)
ctx.fillText(numberY * -1, heightTextY, n);
}
</script>
最佳答案
我之前也被这个问题搞糊涂了,不过最后解决了。
事实上,我们必须模拟一个支持缩放和平移的 Canvas 视口(viewport)。
这里我列出了缩放和平移的解决方案。
您可以先运行下面的代码来查看结果(用鼠标放大或缩小),而不是先分析代码细节,如果这是您想要的,那么您可以在代码中找到答案。
class ViewPort {
constructor(canvas) {
this.canvas = canvas
/**
* Point used to calculate the change of every point's position on
* canvas after view port is zoomed and panned
*/
this.center = this.basicCenter
this.zoom = 1
this.shouldPan = false
this.prevZoomingPoint = null
}
get canvasWidth() {
return this.canvas.getBoundingClientRect().width
}
get canvasHeight() {
return this.canvas.getBoundingClientRect().height
}
get canvasLeft() {
return this.canvas.getBoundingClientRect().left
}
get canvasTop() {
return this.canvas.getBoundingClientRect().top
}
get context() {
return this.canvas.getContext('2d')
}
get basicCenter() {
const { canvasWidth, canvasHeight } = this
const point = {
x: canvasWidth / 2,
y: canvasHeight / 2
}
return point
}
get basicWidth() {
const width = this.canvasWidth
return width
}
get basicHeight() {
const height = this.canvasHeight
return height
}
get width() {
const { basicWidth, zoom } = this
const width = basicWidth * zoom
return width
}
get height() {
const { basicHeight, zoom } = this
const height = basicHeight * zoom
return height
}
get movement() {
const { width, height, basicWidth, basicHeight } = this
const { x: cx, y: cy } = this.center
const { x: basicCX, y: basicCY } = this.basicCenter
const deltaX = cx - basicCX - ((width - basicWidth) / 2)
const deltaY = cy - basicCY - ((height - basicHeight) / 2)
const res = {
x: deltaX,
y: deltaY
}
return res
}
get pan() {
const { center, zoom, basicCenter } = this
const res = {
x: center.x - basicCenter.x,
y: center.y - basicCenter.y
}
return res
}
zoomBy(center, deltaZoom) {
const prevZoom = this.zoom
this.zoom = this.zoom + deltaZoom
this.center = this.zoomPoint(center, this.zoom / prevZoom, this.center)
}
zoomIn(point) {
this.zoomBy(point, 0.1)
}
zoomOut(point) {
this.zoom > 0.25 && this.zoomBy(point, -0.1)
}
zoomPoint(center, rate, point) {
const { x: cx, y: cy } = center
const { x, y } = point
const deltaX = (x - cx) * rate
const deltaY = (y - cy) * rate
const newPoint = {
x: cx + deltaX,
y: cy + deltaY
}
return newPoint
}
panBy(deltaX, deltaY) {
const { x: centerX, y: centerY } = this.center
this.center = {
x: centerX + deltaX,
y: centerY + deltaY
}
}
getDeltaPointToPrevPanningPoint(point) {
const { x, y } = point
const { x: prevX, y: prevY } = this.prevZoomingPoint
const deltaPoint = {
x: x - prevX,
y: y - prevY
}
return deltaPoint
}
startPan(event) {
const point = {
x: event.x - this.canvasLeft,
y: event.y - this.canvasTop,
}
this.shouldPan = true
this.prevZoomingPoint = point
}
panning(event) {
const point = {
x: event.x - this.canvasLeft,
y: event.y - this.canvasTop,
}
const deltaX = this.getDeltaPointToPrevPanningPoint(point).x
const deltaY = this.getDeltaPointToPrevPanningPoint(point).y
this.prevZoomingPoint = point
this.panBy(deltaX, deltaY)
}
stopPan() {
this.shouldPan = false
}
transformToInitial(point) {
const { x, y } = point
const { movement, zoom } = this
const res = {
x: (x - movement.x) / zoom,
y: (y - movement.y) / zoom
}
return res
}
transform(point) {
const { x, y } = point
const { movement, zoom } = this
const res = {
x: x * zoom + movement.x,
y: y * zoom + movement.y
}
return res
}
clearCanvas() {
this.context.setTransform(1, 0, 0, 1, 0, 0)
this.context.clearRect(
0,
0,
viewPort.canvasWidth,
viewPort.canvasHeight
)
}
}
class Interaction {
constructor({
canvas,
viewPort,
dragger
}) {
canvas.removeEventListener("mousewheel", mousewheelListener)
canvas.addEventListener("mousewheel", mousewheelListener)
canvas.removeEventListener("mousedown", mousedownListener)
canvas.addEventListener("mousedown", mousedownListener)
canvas.removeEventListener("mousemove", mousemoveListener)
canvas.addEventListener("mousemove", mousemoveListener)
canvas.removeEventListener("mouseup", mouseupListener)
canvas.addEventListener("mouseup", mouseupListener)
function mousewheelListener(event) {
event.preventDefault()
const point = {
x: event.x - canvas.getBoundingClientRect().left,
y: event.y - canvas.getBoundingClientRect().top,
}
const { deltaX, deltaY } = event
if (isDecreasing()) {
viewPort.zoomIn(point)
}
if (isIncreasing()) {
viewPort.zoomOut(point)
}
function isIncreasing() {
const res = deltaX > 0 || deltaY > 0
return res
}
function isDecreasing() {
const res = deltaX < 0 || deltaY < 0
return res
}
render()
}
function mousedownListener(event) {
viewPort.startPan(event)
}
function mousemoveListener(event) {
viewPort.shouldPan && viewPort.panning(event)
viewPort.shouldPan && render()
}
function mouseupListener(event) {
viewPort.stopPan(event)
}
}
}
const canvas = document.getElementById("myCanvas")
const viewPort = new ViewPort(canvas)
const interaction = new Interaction({ viewPort, canvas })
function render() {
const { abs, max } = Math
const { zoom, movement, context: ctx, pan, center, basicCenter } = viewPort
viewPort.clearCanvas()
ctx.setTransform(zoom, 0, 0, zoom, movement.x, movement.y)
// Original codes are rewrote
const { canvasWidth, canvasHeight } = viewPort
const interval = 20
const basicWidth = canvasWidth
const basicHeight = canvasHeight
const potentialWidth = 2 * max(abs(viewPort.transformToInitial({ x: 0, y: 0 }).x - basicCenter.x), abs(viewPort.transformToInitial({ x: basicWidth, y: 0 }).x - basicCenter.x))
const width = potentialWidth > basicWidth ? potentialWidth : basicWidth
const potentialHeight = 2 * max(abs(viewPort.transformToInitial({ x: 0, y: 0 }).y - basicCenter.y), abs(viewPort.transformToInitial({ x: 0, y: basicHeight }).y - basicCenter.y))
const height = potentialHeight > basicHeight ? potentialHeight : basicHeight
drawXAxis()
drawYAxis()
drawOriginCoordinate()
drawXCoordinates()
drawYCoordinates()
function drawXAxis() {
const path = new Path2D
path.moveTo(basicCenter.x - width / 2, basicHeight / 2)
path.lineTo(basicCenter.x + width / 2, basicHeight / 2)
ctx.stroke(path)
}
function drawYAxis() {
const path = new Path2D
path.moveTo(basicWidth / 2, basicCenter.y - height / 2)
path.lineTo(basicWidth / 2, basicCenter.y + height / 2)
ctx.stroke(path)
}
function drawOriginCoordinate() {
ctx.fillText(`O`, basicCenter.x + 5, basicCenter.y - 5)
}
function drawXCoordinates() {
for (let i = 1; i <= width / 2 / interval; i++) {
total = i * interval
ctx.fillText(` ${i} `, basicCenter.x + total, basicHeight / 2)
}
for (let i = 1; i <= width / 2 / interval; i++) {
total = i * interval
ctx.fillText(` -${i} `, basicCenter.x - total, basicHeight / 2)
}
}
function drawYCoordinates() {
for (let i = 1; i <= height / 2 / interval; i++) {
total = i * interval
ctx.fillText(` ${i} `, basicWidth / 2, basicCenter.y + total)
}
for (let i = 1; i <= height / 2 / interval; i++) {
total = i * interval
ctx.fillText(` -${i} `, basicWidth / 2, basicCenter.y - total)
}
}
}
render()
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
关于javascript - 用鼠标放大我的 Canvas (坐标系),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49478866/
我一直在试图弄清楚小部件的坐标是如何到达的。例如在 qt 文档中,我想知道这是如何完成的。 QGridLayout *layout = new QGridLayout; layout->ad
我正在尝试在 libGDX 中正确配置我的 Camera 和 Sprite,以正确显示在 2D 坐标系中,原点位于左下角。 我像这样设置我的相机: cameraWidth = Gdx.graphics
我最近查看了 App Store 中提供的 Swift Playgrounds 应用程序,在那里我偶然发现了这个交互式坐标系 View ,类似于可以在 Mac 上的 Xcode playgrounds
我知道 Posit 会计算相机和 3d 对象之间的平移和旋转。我现在唯一的问题是,我不知道相机和物体的坐标系是如何定义的。因此,例如,如果我绕 z 轴旋转 90°,z 轴指向哪个方向,物体是绕这个轴旋
我想完成以下事情。我有一组PDF文件,首先我想检查坐标系的原点。如果 pdf 坐标系的原点不是左上角 [通常原点在左下角],我想创建一个坐标在左上角的结果 PDF。我正在尝试使用 PDFBox [下面
我有来自 AVAsset 的 CVPixelBufferRef。我正在尝试对其应用 CIFilter。我使用这些行: CVPixelBufferRef pixelBuffer = ... CVPixe
我很难理解 OpenLayers 使用的坐标系。 英国莱斯特大约在。 Latitude: 52.63973017532399 Longitude: -1.142578125 但要使用 OpenLay
我刚开始iOS绘图编程,发现坐标系和Mac OS X不同,基本上iOS上的原点在左上角,而不是像Mac上的左下角。只是想知道是否有人知道 Apple 为何做出此更改,以及 Mac 的 future 也
我想更改 PDF 坐标系以更改原点 (0,0) -> 从左下角到左上角。因此,例如,当我在 x=5 y=10 的位置书写文本时,它将以从左数起 10 点和从上数(而不是从下数)开始的 10 点书写。
我有以下代码: QGraphicsScene* pScene = new QGraphicsScene(this); ui->graphicsView->setScene(pScene); pScen
我目前正在尝试实现一个基于室内地图的 AR 浏览器,但我面临几个问题,让我们看一下图: 在这个图中,我已经将坐标更改为OpenGL的右手坐标系。 在我们的真实场景中, 给定角度 FOV/2 和相机高度
我正在尝试在 ios 中构建自定义 warp 内核。 我有这个内核代码 var kernelCode = " kernel vec2 partialFlip(vec2 center,
我在我的旧手机 (Samsung Galaxy Ace) 上测试我的“游戏”,我把它给了我妈妈,所以我现在使用的是平板电脑 (Samsung GT-P7300),但我在当我触摸屏幕时的坐标。我在 An
我正在开发一个网络应用程序,它包括一个我绘制函数图形的部分,坐标系是由 Canvas 制作的。问题是,我无法放大坐标系。我想让它能够放大和缩小+使用鼠标移动坐标系。放大/缩小时,x 和 y 值也应该增
我的问题类似于Changing sensor coordinate system in android 无论设备方向如何,我都希望能够相互比较用户的 Action 。因此,当用户以纵向握住手机并弯曲
我正在尝试使用 stereoRectify。我没有使用 stereoCalibrate 校准我的相机,而是已经有了一些信息,我将使用这些信息来创建相机矩阵,这些矩阵是 stereoRectify 的输
我在矩阵中有一个对象的足迹,简而言之,对象占用了哪些单元格(对象是一个部分,标记为 0 的单元格未被占用,标记为 1 的单元格被对象占用)。然后,我在 list > 中有一个已占用单元格的列表。与矩阵
我是 Canvas 的新手,想知道: 使用倒笛卡尔坐标系的基本原理。 比如说,我需要在直方图中绘制一些值。是一种将 Canvas 框架旋转/映射到笛卡尔坐标系的简单方法。? 最佳答案 Canvas 是
通读 SVG 1.1 specification ,我试图了解用于定义初始视口(viewport)的单位与文档其余部分使用的单位之间的关系。 如果视口(viewport)最初是使用点定义的 并且文档
好的,所以我找到了这个 thread ,这是我认为我需要做的。但是,我使用的不是 GL10,而是 GLES20。 glOrthof 不是 GLES20 API 的一部分。 我想做的是改变坐标系的范围,
我是一名优秀的程序员,十分优秀!